<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\ThirdPartyBundle\Search;

use Chill\MainBundle\Search\SearchApiInterface;
use Chill\MainBundle\Search\SearchApiQuery;
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;

/*
 * Internal note: test query for parametrizing / testing:
 *
WITH rows AS (
    SELECT 'aide a domicile en milieu rural admr' AS c, 'la roche sur yon' AS l
    UNION
    SELECT 'aide a domicile en milieu rural admr' AS c, 'fontenay-le-comte' AS l
), searches AS (
    SELECT 'admr roche' AS s, 'admr' AS s1, 'roche' As s2
    UNION
    SELECT 'admr font' AS s, 'admr' AS s1, 'font' AS s2
)
SELECT
    c, l, s, s1, s2,
    strict_word_similarity(s, c)
        + (c LIKE '%' || s1 || '%')::int
        + (c LIKE '%' || s2 || '%')::int
        + (l LIKE '%' || s1 || '%')::int
        + (l LIKE '%' || s2 || '%')::int,
    l LIKE '%' || s1 || '%',
    l LIKE '%' || s2 || '%'
FROM rows, searches
 */

/**
 * Generate query for searching amongst third parties.
 */
class ThirdPartyApiSearch implements SearchApiInterface
{
    public function __construct(private readonly ThirdPartyRepository $thirdPartyRepository) {}

    public function getResult(string $key, array $metadata, float $pertinence)
    {
        return $this->thirdPartyRepository->find($metadata['id']);
    }

    public function prepare(array $metadatas): void {}

    public function provideQuery(string $pattern, array $parameters): SearchApiQuery
    {
        $query = (new SearchApiQuery())
            ->setSelectKey('tparty')
            ->setSelectJsonbMetadata("jsonb_build_object('id', tparty.id)")
            ->setFromClause('chill_3party.third_party AS tparty
                LEFT JOIN chill_3party.third_party AS parent ON tparty.parent_id = parent.id
                LEFT JOIN chill_main_address cma ON cma.id = COALESCE(parent.address_id, tparty.address_id)
                LEFT JOIN chill_main_postal_code cmpc ON cma.postcode_id = cmpc.id');

        $strs = \explode(' ', $pattern);
        $wheres = [];
        $whereArgs = [];
        $pertinence = [];
        $pertinenceArgs = [];

        foreach ($strs as $str) {
            if ('' !== trim($str)) {
                $wheres[] = "((LOWER(UNACCENT(?)) <<% tparty.canonicalized OR
                    tparty.canonicalized LIKE '%' || LOWER(UNACCENT(?)) || '%')
                    OR
                    (LOWER(UNACCENT(?)) <<% parent.canonicalized OR
                    parent.canonicalized LIKE '%' || LOWER(UNACCENT(?)) || '%'))
                    ";
                $whereArgs[] = [$str, $str, $str, $str];
                $pertinence[] = 'GREATEST(
                        STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), tparty.canonicalized),
                        STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), parent.canonicalized)
                    ) + '.
                    "GREATEST(
                        (tparty.canonicalized LIKE '%s' || LOWER(UNACCENT(?)) || '%')::int,
                        (parent.canonicalized LIKE '%s' || LOWER(UNACCENT(?)) || '%')::int
                    ) + ".
                   // take postcode label into account, but lower than the canonicalized field
                   "COALESCE((LOWER(UNACCENT(cmpc.label)) LIKE '%' || LOWER(UNACCENT(?)) || '%')::int * 0.3, 0)";
                $pertinenceArgs[] = [$str, $str, $str, $str, $str];
            }
        }

        $query
            ->setSelectPertinence(\implode(' + ', $pertinence).' + 1', \array_merge(
                [],
                ...$pertinenceArgs
            ))
            ->andWhereClause(\implode(' AND ', $wheres)
                .' AND tparty.active IS TRUE and (parent.active IS TRUE OR parent IS NULL)', \array_merge(
                    [],
                    ...$whereArgs
                ));

        return $query;
    }

    public function supportsResult(string $key, array $metadatas): bool
    {
        return 'tparty' === $key;
    }

    public function supportsTypes(string $pattern, array $types, array $parameters): bool
    {
        return \in_array('thirdparty', $types, true);
    }
}
