<?php

declare(strict_types=1);

namespace ImovelZapAi\Importing\Application\Actions;

use ImovelZapAi\Importing\Application\Services\ImportLogWriter;
use ImovelZapAi\Importing\Domain\Enums\ImportJobStatus;
use ImovelZapAi\Importing\Domain\Enums\ImportLogEvent;
use ImovelZapAi\Importing\Domain\Exceptions\ImportException;
use ImovelZapAi\Importing\Infrastructure\Persistence\Eloquent\ImportErrorModel;
use ImovelZapAi\Importing\Infrastructure\Persistence\Eloquent\ImportJobModel;

final class UpdateImportMappingAction
{
    public function __construct(
        private readonly ImportLogWriter $logWriter,
    ) {}

    /**
     * @param  array<string, mixed>  $mappingPatch
     */
    public function execute(ImportJobModel $job, array $mappingPatch): ImportJobModel
    {
        if (! in_array($job->status, [
            ImportJobStatus::PreviewReady,
            ImportJobStatus::AwaitingMapping,
            ImportJobStatus::Ready,
        ], true)) {
            throw ImportException::invalidState(
                $job->status instanceof ImportJobStatus ? $job->status->value : (string) $job->status,
                'mapping',
            );
        }

        $current = $job->mapping ?? [];
        $merged = [
            'property_types' => array_merge($current['property_types'] ?? [], $mappingPatch['property_types'] ?? []),
            'purposes' => array_merge($current['purposes'] ?? [], $mappingPatch['purposes'] ?? []),
            'states' => array_merge($current['states'] ?? [], $mappingPatch['states'] ?? []),
            'cities' => array_merge($current['cities'] ?? [], $mappingPatch['cities'] ?? []),
            'neighborhoods' => array_merge($current['neighborhoods'] ?? [], $mappingPatch['neighborhoods'] ?? []),
            'issues' => array_merge($current['issues'] ?? [], $mappingPatch['issues'] ?? []),
        ];

        foreach ($mappingPatch['issue_resolutions'] ?? [] as $errorId => $resolution) {
            ImportErrorModel::query()
                ->where('import_job_id', $job->id)
                ->whereKey($errorId)
                ->update([
                    'resolution' => (string) $resolution,
                    'status' => 'resolved',
                ]);
        }

        $preview = $job->preview_summary ?? [];
        $ambiguities = [];
        foreach ($preview['ambiguities'] ?? [] as $item) {
            $field = $item['field'] ?? null;
            $key = $item['key'] ?? null;
            if ($field === null || $key === null) {
                continue;
            }

            $bucket = match ($field) {
                'property_type' => 'property_types',
                'purpose' => 'purposes',
                'state' => 'states',
                'city' => 'cities',
                'neighborhood' => 'neighborhoods',
                default => null,
            };

            if ($bucket === null || empty($merged[$bucket][$key])) {
                $ambiguities[] = $item;
            }
        }

        $status = $ambiguities === []
            ? (($job->error_listings ?? 0) > 0 ? ImportJobStatus::PreviewReady : ImportJobStatus::Ready)
            : ImportJobStatus::AwaitingMapping;

        $preview['ambiguities'] = $ambiguities;

        $job->forceFill([
            'mapping' => $merged,
            'preview_summary' => $preview,
            'status' => $status,
        ])->save();

        $this->logWriter->write(
            $job->tenant_id,
            $job->id,
            ImportLogEvent::MappingUpdated,
            message: 'Mapeamento atualizado.',
        );

        return $job->fresh(['errors', 'file']);
    }
}
