<?php
declare(strict_types=1);

namespace Celena\Plugin\Shop\Admin;

use Celena\Core\Database\Connection;
use Celena\Core\Http\Pagination;
use Celena\Core\Http\Request;
use Celena\Core\Http\Response;
use Celena\Core\Security\Auth;
use Celena\Core\Security\Csrf;
use Celena\Core\Security\Filter;
use Celena\Core\Template\Engine;
use Celena\Module\AdminBase\AdminController;
use Celena\Module\Settings\Options;

final class PromoCodesAdminController extends AdminController
{
    private function tr(): \Celena\Core\I18n\Translator
    {
        return \Celena\Core\Kernel::container()->make(\Celena\Core\I18n\Translator::class);
    }

    public function __construct(
        Engine $engine,
        Auth $auth,
        Options $options,
        private readonly Connection $conn,
    ) {
        parent::__construct($engine, $auth, $options);
    }

    public function index(Request $request): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        $page = Filter::int($request->query('page', 1), 1);
        $total = $this->conn->builder('shop_promo_codes')->count();
        $p = new Pagination($page, 25, $total);
        $rows = $this->conn->builder('shop_promo_codes')
            ->orderBy('id', 'desc')
            ->limit($p->perPage)->offset($p->offset)->get();

        return $this->view('plugins/shop/admin/promocodes_index', [
            'codes' => $rows,
            'pagination' => $p->toArray('/admin/shop/promocodes?page=:page'),
            'total' => $total,
        ], 'shop-promocodes', $this->tr()->translate('shop.promocodes_list.title'));
    }

    public function create(Request $request): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        return $this->view('plugins/shop/admin/promocodes_form', [
            'row' => $this->emptyRow(),
            'form_action' => '/admin/shop/promocodes/create',
        ], 'shop-promocodes', $this->tr()->translate('shop.promocodes_list.new'));
    }

    public function store(Request $request): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        if (!Csrf::validate((string) $request->input('_csrf'))) {
            return $this->redirect('/admin/shop/promocodes/create', $this->tr()->translate('shop.flash.csrf'), 'error');
        }
        $data = $this->extract($request);
        if ($data['code'] === '') {
            return $this->redirect('/admin/shop/promocodes/create', $this->tr()->translate('shop.flash.code_required'), 'error');
        }
        if ($this->codeExists($data['code'])) {
            return $this->redirect('/admin/shop/promocodes/create', $this->tr()->translate('shop.flash.code_already_exists'), 'error');
        }
        $now = date('Y-m-d H:i:s');
        $data['created_at'] = $now;
        $data['updated_at'] = $now;
        $this->conn->builder('shop_promo_codes')->insert($data);
        return $this->redirect('/admin/shop/promocodes', $this->tr()->translate('shop.flash.promo_created'));
    }

    public function edit(Request $request, array $params): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        $id = Filter::int($params['id'] ?? 0);
        $row = $this->conn->builder('shop_promo_codes')->where('id', '=', $id)->first();
        if ($row === null) return $this->redirect('/admin/shop/promocodes', $this->tr()->translate('shop.flash.not_found'), 'error');
        return $this->view('plugins/shop/admin/promocodes_form', [
            'row' => $row,
            'form_action' => '/admin/shop/promocodes/' . $id . '/update',
        ], 'shop-promocodes', 'Промокод: ' . $row['code']);
    }

    public function update(Request $request, array $params): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        if (!Csrf::validate((string) $request->input('_csrf'))) {
            return $this->redirect('/admin/shop/promocodes', $this->tr()->translate('shop.flash.csrf'), 'error');
        }
        $id = Filter::int($params['id'] ?? 0);
        $existing = $this->conn->builder('shop_promo_codes')->where('id', '=', $id)->first();
        if ($existing === null) return $this->redirect('/admin/shop/promocodes', $this->tr()->translate('shop.flash.not_found'), 'error');
        $data = $this->extract($request);
        if ($data['code'] !== $existing['code'] && $this->codeExists($data['code'])) {
            return $this->redirect('/admin/shop/promocodes/' . $id . '/edit', $this->tr()->translate('shop.flash.code_taken'), 'error');
        }
        $data['updated_at'] = date('Y-m-d H:i:s');
        $this->conn->builder('shop_promo_codes')->where('id', '=', $id)->update($data);
        return $this->redirect('/admin/shop/promocodes', $this->tr()->translate('shop.flash.saved'));
    }

    public function delete(Request $request, array $params): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        if (!Csrf::validate((string) $request->input('_csrf'))) {
            return $this->redirect('/admin/shop/promocodes', $this->tr()->translate('shop.flash.csrf'), 'error');
        }
        $id = Filter::int($params['id'] ?? 0);
        $this->conn->builder('shop_promo_codes')->where('id', '=', $id)->delete();
        return $this->redirect('/admin/shop/promocodes', $this->tr()->translate('shop.flash.deleted'));
    }

    private function emptyRow(): array
    {
        return [
            'id' => 0, 'code' => '', 'type' => 'percent', 'value' => 0,
            'min_amount' => '', 'usage_limit' => '', 'usage_count' => 0,
            'starts_at' => '', 'ends_at' => '', 'is_active' => true, 'comment' => '',
        ];
    }

    private function extract(Request $request): array
    {
        $type = (string) $request->input('type', 'percent');
        if (!in_array($type, ['percent', 'fixed', 'free_shipping'], true)) {
            $type = 'percent';
        }
        $minAmount = (string) $request->input('min_amount', '');
        $usageLimit = (string) $request->input('usage_limit', '');
        $startsAt = (string) $request->input('starts_at', '');
        $endsAt = (string) $request->input('ends_at', '');
        return [
            'code'        => mb_strtoupper(trim((string) $request->input('code', '')), 'UTF-8'),
            'type'        => $type,
            'value'       => (float) $request->input('value', 0),
            'min_amount'  => $minAmount === '' ? null : (float) $minAmount,
            'usage_limit' => $usageLimit === '' ? null : (int) $usageLimit,
            'starts_at'   => $startsAt === '' ? null : $startsAt,
            'ends_at'     => $endsAt === '' ? null : $endsAt,
            'is_active'   => Filter::bool($request->input('is_active')),
            'comment'     => Filter::string($request->input('comment'), 1000),
        ];
    }

    private function codeExists(string $code): bool
    {
        return $this->conn->builder('shop_promo_codes')->where('code', '=', $code)->first() !== null;
    }
}
