<?php

declare(strict_types=1);

namespace App\Business\DataImport\Handlers;

use App\Business\DataImport\DataImportRow;
use App\Business\DataImport\DataImportRowPrecheckOutcome;
use App\Business\DataImport\Enums\DataImportRowStatus;
use App\Business\DataImport\Support\DataImportRowSnapshotEncoder;
use App\Business\DataImport\Support\DataImportValueParser;
use Illuminate\Database\Eloquent\Model;

abstract class AbstractMasterDataImportHandler
{
    /**
     * @param  list<DataImportRow>  $rows
     * @return list<DataImportRowPrecheckOutcome>
     */
    protected function buildInitialOutcomes(array $rows): array
    {
        $outcomes = [];

        foreach ($rows as $row) {
            $outcomes[] = new DataImportRowPrecheckOutcome(
                rowNumber: $row->rowNumber,
                status: DataImportRowStatus::Validated,
                rawSnapshot: DataImportRowSnapshotEncoder::fromRow($row),
            );
        }

        return $outcomes;
    }

    /**
     * @param  list<DataImportRowPrecheckOutcome>  $outcomes
     * @param  list<string>  $errorMessages
     * @return list<DataImportRowPrecheckOutcome>
     */
    protected function markRowFailed(array $outcomes, int $rowNumber, array $errorMessages): array
    {
        foreach ($outcomes as $index => $outcome) {
            if ($outcome->rowNumber !== $rowNumber) {
                continue;
            }

            $mergedErrors = array_values(array_unique(array_merge($outcome->errorMessages, $errorMessages)));
            $outcomes[$index] = new DataImportRowPrecheckOutcome(
                rowNumber: $outcome->rowNumber,
                status: DataImportRowStatus::Failed,
                rawSnapshot: $outcome->rawSnapshot,
                errorMessages: $mergedErrors,
            );
        }

        return $outcomes;
    }

    /**
     * @param  list<DataImportRow>  $rows
     * @param  list<DataImportRowPrecheckOutcome>  $outcomes
     * @return list<DataImportRowPrecheckOutcome>
     */
    protected function applyDuplicateFieldErrors(
        array $rows,
        array $outcomes,
        string $field,
        string $duplicateMessageKey,
    ): array {
        $groups = DataImportValueParser::groupRowsByFieldValue($rows, $field);

        foreach ($groups as $value => $rowNumbers) {
            if (count($rowNumbers) <= 1) {
                continue;
            }

            foreach ($rowNumbers as $rowNumber) {
                $outcomes = $this->markRowFailed($outcomes, $rowNumber, [
                    DataImportValueParser::rowError($rowNumber, (string) __($duplicateMessageKey, [
                        'value' => $value,
                    ])),
                ]);
            }
        }

        return $outcomes;
    }

    /**
     * @param  list<string>  $values
     * @return list<string>
     */
    protected function loadExistingValues(string $modelClass, string $column, array $values): array
    {
        if ($values === []) {
            return [];
        }

        /** @var class-string<Model> $modelClass */
        return $modelClass::query()
            ->whereIn($column, $values)
            ->pluck($column)
            ->map(static fn ($value): string => (string) $value)
            ->all();
    }

    /**
     * @param  list<DataImportRowPrecheckOutcome>  $outcomes
     * @return list<DataImportRowPrecheckOutcome>
     */
    protected function finalizeOutcomes(array $outcomes): array
    {
        return $outcomes;
    }
}
