<?php

namespace Modules\Facture\Repository;

use Entity\Model\Enum\EFacDematFlowStatus;
use Entity\Model\Enum\EFacDematStatusReason;
use Helpers\Pagination\PaginatorGestion;
use Helpers\QueryBuilder\AbsRepository;
use Helpers\QueryBuilder\SqlExpr;
use Modules\Facture\Service\FactureDematMapper;
use Psr\Container\ContainerInterface;

class FactureDematRepo extends AbsRepository
{

    public function __construct(\PDO $pdo, private ContainerInterface $container)
    {
        parent::__construct($pdo);
    }

//_____________________________________________________________________________
// Flow

    /**
     * @return array<string>
     */
    public function listMappedFacField()
    {
        $mapper = FactureDematMapper::createFromConfig($this->container);
        return $mapper->listField();
    }

    /**
     * @return ?array<mixed>
     */
    public function getFlow(string $id)
    {
        return $this->listFlow(['filter_egal_ID' => $id])[0] ?? null;
    }

    /**
     * @param array<mixed> $post
     * @return array<array<mixed>>
     */
    public function listFlow(array $post): array
    {
        $param = [];
        $req = $this->getMainQuery($post, $param);
        (new PaginatorGestion())->injecterSqlCount($req, $post, $param);

        return array_map(function ($row) {
            return $row + [
                'Status' => EFacDematFlowStatus::tryFrom($row['STATUS']),
                'RefusReason' => EFacDematStatusReason::tryFrom($row['RefusReasonCode']),

                // Assume there is an error if there is not FAC_ENT and the recipient is Oxalys
                'hasValidError' => empty($row['NUM_FACT']) && empty($row['DEST_EXT']),
            ];
        }, $this->fetchAssocAll($req, $param));
    }

    /**
     * @param array<mixed> $post
     */
    public function listFlowExport(array $post) :\PDOStatement
    {
        $param = [];
        return $this->createStatement(
            $this->getMainQuery($post, $param),
            $param
        );
    }

    /**
     * @param array<mixed> $post
     * @param array<mixed> $param
     */
    private function getMainQuery(array $post, array &$param) :string
    {
        $param     = [];
        $listField = implode(',', array_map(
            fn($field) => '[' . $field . ']', // We don't use quoteColumn here since $field may contains non-interpretable '.'
            //[Sql::class, 'qc'],
            $this->listMappedFacField(),
        ));

        $req =
            "SELECT 
                FAC_DEMAT_FLOW.ID,
                FAC_DEMAT_FLOW.PARTN_ID,
                FAC_DEMAT_FLOW.FLOW_ID,
                FAC_DEMAT_FLOW.SUBMITTED,
                FAC_DEMAT_FLOW.UPDATED,
                FAC_DEMAT_FLOW.CREATED,
                FAC_DEMAT_FLOW.DEST_EXT,
                FAC_DEMAT_FLOW.STATUS,
                FAC_DEMAT_FLOW.FIC_UBL,
                FAC_DEMAT_FLOW.FIC_LISIBLE,
                FAC_DEMAT_FLOW.NUM_FACT,
                tFacEnt.*,
                RefusReason.VALUE as RefusReasonCode
            FROM FAC_DEMAT_FLOW with(nolock)
            CROSS APPLY ( /* JOIN TOP 1 */
                SELECT TOP 1 * FROM (
                    SELECT " . $listField . "
                    FROM (
                        SELECT * FROM ENTITYMETA
                        WHERE ENTITYMETA.ENTITY_TYPE = 'FADF' /* FAC_DEMAT_FLOW */
                            AND ENTITYMETA.ENTITY_ID = FAC_DEMAT_FLOW.ID
                            AND ENTITYMETA.STRUCT_TYPE = 'MAPP'
                            AND ENTITYMETA.STRUCT_ID = 0
                    ) as tmp PIVOT (
                        MAX(tmp.VALUE) -- We assume there is only one record
                        FOR tmp.FIELD_KEY IN (" . $listField . ")
                    ) as pivMappage
                ) as tmp
            ) as tFacEnt
            LEFT JOIN ENTITYMETA as RefusReason with(nolock)
                ON RefusReason.ENTITY_TYPE = 'FADF' /* FAC_DEMAT_FLOW */
                AND RefusReason.ENTITY_ID = FAC_DEMAT_FLOW.ID
                AND RefusReason.STRUCT_TYPE = 'FDRR'
                AND RefusReason.STRUCT_ID = 0
                AND RefusReason.FIELD_KEY = 'reasonCode'
            WHERE 1=1 ";

        if (!empty($post['filter_integrable'])) {
            $not  = $post['filter_integrable'] == 'O' ? 'NOT' : '';
            $req .= " AND $not (FAC_DEMAT_FLOW.NUM_FACT = 0 AND FAC_DEMAT_FLOW.DEST_EXT = '') ";
            unset($post['filter_integrable']);
        }

        if (!empty($post['filter_dateIssueYear'])) {
            $post['filter_dateIssueYear'] = new SqlExpr(
                ' SUBSTRING(DATE_FAFO, 1, 4) = :year ',
                [':year' => $post['filter_dateIssueYear']]
            );
        }

        // TODO:   prend en compte le périmètre société de l'utilisateur

        return $this->applyFilter($req, $param, $post);
    }
}
