<?php
declare(strict_types=1);

namespace App\Modules\Settings;

use App\Core\Http\Request;
use App\Core\Http\Response;
use App\Core\I18n\Translator;
use App\Core\Constants\RedirectPaths;
use App\Core\Security\Csrf;
use App\Core\Support\Flash;
use Throwable;

final class AllegroStatusMappingController
{
    public function __construct(
        private readonly Translator $translator,
        private readonly AllegroStatusMappingRepository $statusMappings,
        private readonly OrderStatusRepository $orderStatuses,
        private readonly AllegroStatusDiscoveryService $statusDiscoveryService,
        private readonly ?AllegroPullStatusMappingRepository $pullStatusMappings = null
    ) {
    }

    public function saveStatusMapping(Request $request): Response
    {
        return Response::redirect(RedirectPaths::ALLEGRO_STATUSES_TAB);
    }

    public function saveStatusMappingsBulk(Request $request): Response
    {
        $csrfError = $this->validateCsrf((string) $request->input('_token', ''));
        if ($csrfError !== null) {
            return $csrfError;
        }

        $orderproCodes = $request->input('orderpro_status_code', []);
        $allegroCodes = $request->input('allegro_status_code', []);
        $allegroNames = $request->input('allegro_status_name', []);
        if (!is_array($orderproCodes) || !is_array($allegroCodes) || !is_array($allegroNames)) {
            Flash::set('settings_error', $this->translator->get('settings.allegro.statuses.flash.save_failed'));
            return Response::redirect(RedirectPaths::ALLEGRO_STATUSES_TAB);
        }

        $allowedOrderpro = $this->resolveAllowedOrderproStatusCodes();
        $mappings = [];

        foreach ($orderproCodes as $index => $rawOrderproCode) {
            $orderproCode = strtolower(trim((string) $rawOrderproCode));
            if ($orderproCode === '' || !isset($allowedOrderpro[$orderproCode])) {
                continue;
            }

            $allegroCode = strtolower(trim((string) ($allegroCodes[$index] ?? '')));
            if ($allegroCode === '') {
                continue;
            }

            $allegroName = trim((string) ($allegroNames[$index] ?? ''));

            $mappings[] = [
                'orderpro_status_code' => $orderproCode,
                'allegro_status_code' => $allegroCode,
                'allegro_status_name' => $allegroName,
            ];
        }

        try {
            $this->statusMappings->replaceAllMappings($mappings);
            Flash::set('settings_success', $this->translator->get('settings.allegro.statuses.flash.saved_bulk'));
        } catch (Throwable $exception) {
            Flash::set('settings_error', $this->translator->get('settings.allegro.statuses.flash.save_failed') . ' ' . $exception->getMessage());
        }

        return Response::redirect(RedirectPaths::ALLEGRO_STATUSES_TAB);
    }

    public function deleteStatusMapping(Request $request): Response
    {
        $csrfError = $this->validateCsrf((string) $request->input('_token', ''));
        if ($csrfError !== null) {
            return $csrfError;
        }

        $mappingId = max(0, (int) $request->input('mapping_id', 0));
        if ($mappingId <= 0) {
            Flash::set('settings_error', $this->translator->get('settings.allegro.statuses.flash.mapping_not_found'));
            return Response::redirect(RedirectPaths::ALLEGRO_STATUSES_TAB);
        }

        try {
            $this->statusMappings->deleteMappingById($mappingId);
            Flash::set('settings_success', $this->translator->get('settings.allegro.statuses.flash.deleted'));
        } catch (Throwable $exception) {
            Flash::set('settings_error', $this->translator->get('settings.allegro.statuses.flash.delete_failed') . ' ' . $exception->getMessage());
        }

        return Response::redirect(RedirectPaths::ALLEGRO_STATUSES_TAB);
    }

    public function savePullStatusMappings(Request $request): Response
    {
        $csrfError = $this->validateCsrf((string) $request->input('_token', ''));
        if ($csrfError !== null) {
            return $csrfError;
        }

        if ($this->pullStatusMappings === null) {
            Flash::set('settings_error', $this->translator->get('settings.allegro.statuses.flash.save_failed'));
            return Response::redirect(RedirectPaths::ALLEGRO_STATUSES_TAB);
        }

        $allegroCodes = $request->input('allegro_status_code', []);
        $allegroNames = $request->input('allegro_status_name', []);
        $orderproCodes = $request->input('orderpro_status_code', []);
        if (!is_array($allegroCodes) || !is_array($allegroNames) || !is_array($orderproCodes)) {
            Flash::set('settings_error', $this->translator->get('settings.allegro.statuses.flash.save_failed'));
            return Response::redirect(RedirectPaths::ALLEGRO_STATUSES_TAB);
        }

        $mappings = [];
        foreach ($allegroCodes as $index => $rawAllegroCode) {
            $allegroCode = strtolower(trim((string) $rawAllegroCode));
            if ($allegroCode === '') {
                continue;
            }

            $allegroName = trim((string) ($allegroNames[$index] ?? ''));
            $orderproCode = strtolower(trim((string) ($orderproCodes[$index] ?? '')));

            $mappings[] = [
                'allegro_status_code' => $allegroCode,
                'allegro_status_name' => $allegroName,
                'orderpro_status_code' => $orderproCode,
            ];
        }

        try {
            $this->pullStatusMappings->replaceAll($mappings);
            Flash::set('settings_success', $this->translator->get('settings.allegro.statuses.flash.saved_pull'));
        } catch (Throwable $exception) {
            Flash::set('settings_error', $this->translator->get('settings.allegro.statuses.flash.save_failed') . ' ' . $exception->getMessage());
        }

        return Response::redirect(RedirectPaths::ALLEGRO_STATUSES_TAB);
    }

    public function syncStatusesFromAllegro(Request $request): Response
    {
        $csrfError = $this->validateCsrf((string) $request->input('_token', ''));
        if ($csrfError !== null) {
            return $csrfError;
        }

        try {
            $result = $this->statusDiscoveryService->discoverAndStoreStatuses(5, 100);
            Flash::set(
                'settings_success',
                $this->translator->get('settings.allegro.statuses.flash.sync_ok', [
                    'discovered' => (string) ((int) ($result['discovered'] ?? 0)),
                    'samples' => (string) ((int) ($result['samples'] ?? 0)),
                ])
            );
        } catch (Throwable $exception) {
            Flash::set('settings_error', $this->translator->get('settings.allegro.statuses.flash.sync_failed') . ' ' . $exception->getMessage());
        }

        return Response::redirect(RedirectPaths::ALLEGRO_STATUSES_TAB);
    }

    /**
     * @return array<string, true>
     */
    private function resolveAllowedOrderproStatusCodes(): array
    {
        $allowed = [];
        foreach ($this->orderStatuses->listStatuses() as $row) {
            $code = strtolower(trim((string) ($row['code'] ?? '')));
            if ($code !== '') {
                $allowed[$code] = true;
            }
        }

        return $allowed;
    }

    private function validateCsrf(string $token): ?Response
    {
        if (Csrf::validate($token)) {
            return null;
        }

        Flash::set('settings_error', $this->translator->get('auth.errors.csrf_expired'));
        return Response::redirect(RedirectPaths::ALLEGRO_INTEGRATION);
    }
}
