<?php

/**
 * Rate Import Controller – GForce Module
 *
 * @category    PortalPeople
 * @package     GForce
 * @author      Portal People Development Team
 * @copyright   Copyright (c) 2026 Portal People (https://portalpeople.co.uk)
 */

namespace PortalPeople\gforce\controllers;

use Yii;
use yii\web\Controller;
use yii\web\UploadedFile;
use yii\filters\AccessControl;
use PortalPeople\gforce\components\RateSheetImporter;
use PortalPeople\gforce\models\RateUploadForm;

/**
 * RateImportController
 *
 * Single-step upload of a GForce pricing spreadsheet that creates one
 * Shippingcosts record per individual postcode (no consolidation step).
 */
class RateImportController extends Controller
{
    private const PREVIEW_SESSION_KEY = 'gforceRateImportPreview';

    /** @inheritdoc */
    public function behaviors(): array
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ],
        ];
    }

    /**
     * Upload form (GET) and direct import pipeline (POST).
     */
    public function actionIndex(): mixed
    {
        $form = new RateUploadForm();
        $request = Yii::$app->request;

        if ($request->isPost && $request->post('confirmImport') === '1') {
            return $this->runConfirmedImport((string) $request->post('previewToken', ''));
        }

        if ($request->isPost) {
            $form->priceFile = UploadedFile::getInstance($form, 'priceFile');

            if ($form->validate()) {
                $ext = $form->priceFile->extension;
                $tmp = tempnam(sys_get_temp_dir(), 'pp_gforce_rate_') . '.' . $ext;

                try {
                    $form->priceFile->saveAs($tmp);

                    $importer = new RateSheetImporter();
                    $preview = $importer->preview($tmp);
                    $token = bin2hex(random_bytes(16));

                    $this->storePreviewUpload($token, $tmp);

                    return $this->render('preview', [
                        'preview' => $preview,
                        'token' => $token,
                        'originalName' => $form->priceFile->name,
                    ]);
                } catch (\Throwable $e) {
                    $form->addError('priceFile', 'Preview failed: ' . $e->getMessage());
                    Yii::warning('RateSheetImporter preview failed: ' . $e->getMessage(), __METHOD__);

                    if (file_exists($tmp)) {
                        unlink($tmp);
                    }
                }
            }
        }

        return $this->render('upload', ['form' => $form]);
    }

    private function runConfirmedImport(string $token): mixed
    {
        $tmpPath = $this->consumePreviewUpload($token);

        if ($tmpPath === null) {
            Yii::$app->session->setFlash('error', 'Your import preview expired. Please upload the file again.');
            return $this->redirect(['index']);
        }

        try {
            $importer = new RateSheetImporter();
            $results  = $importer->import($tmpPath);

            return $this->render('result', ['results' => $results]);
        } catch (\Throwable $e) {
            Yii::$app->session->setFlash('error', 'Import failed: ' . $e->getMessage());
            Yii::warning('RateSheetImporter upload failed: ' . $e->getMessage(), __METHOD__);

            return $this->redirect(['index']);
        } finally {
            if (file_exists($tmpPath)) {
                unlink($tmpPath);
            }
        }
    }

    private function storePreviewUpload(string $token, string $tmpPath): void
    {
        $session = Yii::$app->session;
        $map = (array) $session->get(self::PREVIEW_SESSION_KEY, []);

        $this->clearStalePreviewFiles($map);
        $map[$token] = [
            'tmpPath' => $tmpPath,
            'createdAt' => time(),
        ];

        $session->set(self::PREVIEW_SESSION_KEY, $map);
    }

    private function consumePreviewUpload(string $token): ?string
    {
        if ($token === '') {
            return null;
        }

        $session = Yii::$app->session;
        $map = (array) $session->get(self::PREVIEW_SESSION_KEY, []);
        $entry = $map[$token] ?? null;

        unset($map[$token]);
        $this->clearStalePreviewFiles($map);
        $session->set(self::PREVIEW_SESSION_KEY, $map);

        if (!is_array($entry)) {
            return null;
        }

        $tmpPath = (string) ($entry['tmpPath'] ?? '');
        if ($tmpPath === '' || !file_exists($tmpPath)) {
            return null;
        }

        return $tmpPath;
    }

    /**
     * @param array<string, array{tmpPath?: string, createdAt?: int}> $map
     */
    private function clearStalePreviewFiles(array &$map): void
    {
        $ttlSeconds = 30 * 60;
        $threshold = time() - $ttlSeconds;

        foreach ($map as $token => $entry) {
            $createdAt = (int) ($entry['createdAt'] ?? 0);
            $tmpPath = (string) ($entry['tmpPath'] ?? '');

            if ($createdAt < $threshold) {
                if ($tmpPath !== '' && file_exists($tmpPath)) {
                    unlink($tmpPath);
                }
                unset($map[$token]);
            }
        }
    }
}
