package eu.dnetlib.organizations.repository.readonly;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import eu.dnetlib.organizations.model.view.OrganizationSimpleView;

@Repository
public interface OrganizationSimpleViewRepository extends ReadOnlyRepository<OrganizationSimpleView, String> {

	// SEARCH
	@Query(value = "SELECT \n"
		+ "    org.id,\n"
		+ "    org.name,\n"
		+ "    org.type,\n"
		+ "    org.city,\n"
		+ "    org.country,\n"
		+ "    org.status,\n"
		+ "    array_remove(array_agg(DISTINCT a.acronym), NULL) AS acronyms,\n"
		+ "    array_remove(array_agg(DISTINCT u.url), NULL) AS urls,\n"
		+ "    count(DISTINCT d1.oa_original_id) FILTER (WHERE d1.reltype = 'is_similar') AS n_similar_dups,\n"
		+ "    count(DISTINCT d1.oa_original_id) FILTER (WHERE d1.reltype = 'suggested') AS n_suggested_dups,\n"
		+ "    count(DISTINCT d1.oa_original_id) FILTER (WHERE d1.reltype = 'is_different') AS n_different_dups\n"
		+ "FROM org_index_search idx "
		+ "     JOIN organizations org ON (idx.id = org.id) \n"
		+ "     LEFT OUTER JOIN acronyms a ON org.id = a.id\n"
		+ "     LEFT OUTER JOIN urls u ON org.id = u.id\n"
		+ "     LEFT OUTER JOIN oa_duplicates d1 ON org.id = d1.local_id\n"
		+ "WHERE org.status in :statuses AND (org.name ilike '%'||:text||'%' OR idx.txt @@ plainto_tsquery(:text))\n"
		+ "GROUP BY org.id, org.name, org.type, org.city, org.country, org.status\n"
		+ "ORDER BY org.name", nativeQuery = true)
	Page<OrganizationSimpleView> search(@Param("text") String text, @Param("statuses") List<String> statuses, Pageable pageable);

	// SEARCH FOR USER
	@Query(value = "SELECT\n"
		+ "    org.id,\n"
		+ "    org.name,\n"
		+ "    org.type,\n"
		+ "    org.city,\n"
		+ "    org.country,\n"
		+ "    org.status,\n"
		+ "    array_remove(array_agg(DISTINCT a.acronym), NULL) AS acronyms,\n"
		+ "    array_remove(array_agg(DISTINCT u.url), NULL) AS urls,\n"
		+ "    count(DISTINCT d1.oa_original_id) FILTER (WHERE d1.reltype = 'is_similar'  ) AS n_similar_dups,\n"
		+ "    count(DISTINCT d1.oa_original_id) FILTER (WHERE d1.reltype = 'suggested'   ) AS n_suggested_dups,\n"
		+ "    count(DISTINCT d1.oa_original_id) FILTER (WHERE d1.reltype = 'is_different') AS n_different_dups\n"
		+ "FROM org_index_search idx\n"
		+ "    JOIN organizations org ON (idx.id = org.id)\n"
		+ "    LEFT OUTER JOIN acronyms a ON (org.id = a.id)\n"
		+ "    LEFT OUTER JOIN urls u ON (org.id = u.id)\n"
		+ "    LEFT OUTER JOIN oa_duplicates d1 ON (org.id = d1.local_id)\n"
		+ "    LEFT OUTER JOIN user_countries uc ON (uc.country = org.country) \n"
		+ "WHERE uc.email = :email AND org.status IN :statuses AND (org.name ilike '%'||:text||'%' OR idx.txt @@ plainto_tsquery(:text))\n"
		+ "GROUP BY org.id, org.name, org.type, org.city, org.country, org.status\n"
		+ "ORDER BY org.name", nativeQuery = true)
	Page<OrganizationSimpleView> searchForUser(@Param("text") String text,
		@Param("email") String email,
		@Param("statuses") List<String> statuses,
		Pageable pageable);

	Page<OrganizationSimpleView> findByCountryOrderByName(String country, Pageable pageable);

	Iterable<OrganizationSimpleView> findByCountryOrderByName(String code);

	Iterable<OrganizationSimpleView> findByCountryAndStatusOrderByName(String code, String status);

	Page<OrganizationSimpleView> findByCountryAndStatusOrderByName(String code, String status, Pageable pageable);

	Page<OrganizationSimpleView> findByTypeOrderByName(String type, Pageable pageable);

	Page<OrganizationSimpleView> findByTypeAndStatusOrderByName(String type, String status, Pageable pageable);

	@Query(value = "select o.* from organizations_simple_view o left outer join user_countries uc on (uc.country = o.country) where uc.email = ?2 and o.type = ?1 order by o.name", nativeQuery = true)
	Page<OrganizationSimpleView> findByTypeForUser(String type, String name, Pageable pageable);

	@Query(value = "select o.* from organizations_simple_view o left outer join user_countries uc on (uc.country = o.country) where o.type = ?1 and o.status = ?2 and uc.email = ?3 order by o.name", nativeQuery = true)
	Page<OrganizationSimpleView> findByTypeAndStatusForUser(String type, String status, String name, Pageable pageable);

	// SEARCH FOR VALID DUPLICATE CANDIDATES
	@Query(value = "SELECT\n"
		+ "    org.id,\n"
		+ "    org.name,\n"
		+ "    org.type,\n"
		+ "    org.city,\n"
		+ "    org.country,\n"
		+ "    org.status,\n"
		+ "    array_remove(array_agg(DISTINCT a.acronym), NULL) AS acronyms,\n"
		+ "    array_remove(array_agg(DISTINCT u.url), NULL) AS urls,\n"
		+ "    NULL AS n_similar_dups,\n"
		+ "    NULL AS n_suggested_dups,\n"
		+ "    NULL AS n_different_dups\n"
		+ "FROM org_index_search idx\n"
		+ "    JOIN organizations org ON (idx.id = org.id) \n"
		+ "    LEFT OUTER JOIN acronyms a ON (org.id = a.id)\n"
		+ "    LEFT OUTER JOIN urls u ON (org.id = u.id)\n"
		+ "    LEFT OUTER JOIN oa_duplicates d2 ON (org.id = d2.oa_original_id)\n"
		+ "WHERE org.status = 'raw' AND (org.name ilike '%'||:text||'%' OR idx.txt @@ plainto_tsquery(:text))\n"
		+ "GROUP BY org.id, org.name, org.type, org.city, org.country, org.status\n"
		+ "HAVING  not('is_similar' = ANY(array_agg(d2.reltype)))\n"
		+ "ORDER BY org.name", nativeQuery = true)
	Page<OrganizationSimpleView> searchCandidateDuplicates(@Param("text") String text, Pageable pageable);

	// SEARCH FOR VALID DUPLICATE CANDIDATES FOR USER
	@Query(value = "SELECT\n"
		+ "    org.id,\n"
		+ "    org.name,\n"
		+ "    org.type,\n"
		+ "    org.city,\n"
		+ "    org.country,\n"
		+ "    org.status,\n"
		+ "    array_remove(array_agg(DISTINCT a.acronym), NULL) AS acronyms,\n"
		+ "    array_remove(array_agg(DISTINCT u.url), NULL) AS urls,\n"
		+ "    NULL AS n_similar_dups,\n"
		+ "    NULL AS n_suggested_dups,\n"
		+ "    NULL AS n_different_dups\n"
		+ "FROM org_index_search idx\n"
		+ "    JOIN organizations org ON (idx.id = org.id) \n"
		+ "    LEFT OUTER JOIN acronyms a ON (org.id = a.id)\n"
		+ "    LEFT OUTER JOIN urls u ON (org.id = u.id)\n"
		+ "    LEFT OUTER JOIN oa_duplicates d2 ON (org.id = d2.oa_original_id)\n"
		+ "    LEFT OUTER JOIN user_countries uc ON (uc.country = org.country)\n"
		+ "WHERE org.status = 'raw' AND uc.email = :email AND (org.name ilike '%'||:text||'%' OR idx.txt @@ plainto_tsquery(:text))\n"
		+ "GROUP BY org.id, org.name, org.type, org.city, org.country, org.status\n"
		+ "HAVING  not('is_similar' = ANY(array_agg(d2.reltype)))\n"
		+ "ORDER BY org.name", nativeQuery = true)
	Page<OrganizationSimpleView> searchCandidateDuplicatesForUser(@Param("text") String text, @Param("email") String email, Pageable pageable);

}
