<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Models\VoucherModel;
use App\Helpers\ActivityLogger;
use Core\Request;

final class VoucherController extends BaseController
{
    private VoucherModel $model;

    public function __construct()
    {
        parent::__construct();
        $this->model = new VoucherModel();
    }

    public function index(array $params = []): void
    {
        $this->requirePermission('voucher.view');

        $page    = $this->currentPage();
        $filters = [
            'search'    => Request::get('search', ''),
            'is_active' => Request::get('is_active', ''),
        ];

        $this->view('vouchers.index', [
            'pageTitle'   => 'Vouchers',
            'breadcrumbs' => ['Vouchers' => null],
            'vouchers'    => $this->model->all($page, ITEMS_PER_PAGE, $filters),
            'total'       => $this->model->count($filters),
            'page'        => $page,
            'filters'     => $filters,
        ]);
    }

    public function create(array $params = []): void
    {
        $this->requirePermission('voucher.create');
        $this->view('vouchers.form', [
            'pageTitle'   => 'Create Voucher',
            'breadcrumbs' => ['Vouchers' => url('vouchers'), 'Create' => null],
            'voucher'     => null,
        ]);
    }

    public function store(array $params = []): void
    {
        $this->requirePermission('voucher.create');
        Request::verifyCsrf();

        $errors = $this->validate();
        if ($errors) {
            $this->flash('error', implode('<br>', $errors));
            $this->redirect('/vouchers/create');
        }

        $code = strtoupper(trim(Request::post('code', '')));

        $id = $this->model->create([
            'code'           => $code,
            'description'    => Request::str('description'),
            'discount_type'  => Request::post('discount_type', 'percentage'),
            'discount_value' => Request::float('discount_value'),
            'min_order_amt'  => Request::float('min_order_amt', 0),
            'max_discount'   => Request::float('max_discount') ?: null,
            'usage_limit'    => Request::int('usage_limit') ?: null,
            'per_user_limit' => Request::int('per_user_limit', 1),
            'starts_at'      => Request::post('starts_at'),
            'expires_at'     => Request::post('expires_at'),
            'is_active'      => Request::bool('is_active', true) ? 1 : 0,
            'created_by'     => \Core\Auth::id(),
        ]);

        ActivityLogger::created('voucher', $id, $code);
        $this->flash('success', "Voucher <strong>{$code}</strong> created successfully.");
        $this->redirect('/vouchers');
    }

    public function edit(array $params = []): void
    {
        $this->requirePermission('voucher.edit');

        $voucher = $this->model->find((int)$params['id']);
        if (!$voucher) { $this->flash('error', 'Voucher not found.'); $this->redirect('/vouchers'); }

        $this->view('vouchers.form', [
            'pageTitle'   => 'Edit Voucher',
            'breadcrumbs' => ['Vouchers' => url('vouchers'), 'Edit' => null],
            'voucher'     => $voucher,
        ]);
    }

    public function update(array $params = []): void
    {
        $this->requirePermission('voucher.edit');
        Request::verifyCsrf();

        $id      = (int)$params['id'];
        $voucher = $this->model->find($id);
        if (!$voucher) { $this->flash('error', 'Voucher not found.'); $this->redirect('/vouchers'); }

        $errors = $this->validate($id);
        if ($errors) {
            $this->flash('error', implode('<br>', $errors));
            $this->redirect("/vouchers/{$id}/edit");
        }

        $code = strtoupper(trim(Request::post('code', '')));

        $this->model->update($id, [
            'code'           => $code,
            'description'    => Request::str('description'),
            'discount_type'  => Request::post('discount_type', 'percentage'),
            'discount_value' => Request::float('discount_value'),
            'min_order_amt'  => Request::float('min_order_amt', 0),
            'max_discount'   => Request::float('max_discount') ?: null,
            'usage_limit'    => Request::int('usage_limit') ?: null,
            'per_user_limit' => Request::int('per_user_limit', 1),
            'starts_at'      => Request::post('starts_at'),
            'expires_at'     => Request::post('expires_at'),
            'is_active'      => Request::bool('is_active', true) ? 1 : 0,
        ]);

        ActivityLogger::updated('voucher', $id, $code);
        $this->flash('success', "Voucher <strong>{$code}</strong> updated.");
        $this->redirect('/vouchers');
    }

    public function delete(array $params = []): void
    {
        $this->requirePermission('voucher.delete');
        Request::verifyCsrf();

        $id      = (int)$params['id'];
        $voucher = $this->model->find($id);
        if (!$voucher) { $this->flash('error', 'Voucher not found.'); $this->redirect('/vouchers'); }

        $this->model->delete($id);
        ActivityLogger::deleted('voucher', $id, $voucher['code']);
        $this->flash('success', 'Voucher deleted.');
        $this->redirect('/vouchers');
    }

    public function toggle(array $params = []): void
    {
        $this->requirePermission('voucher.edit');
        Request::verifyCsrf();

        $id      = (int)$params['id'];
        $voucher = $this->model->find($id);
        if (!$voucher) { $this->json(['success' => false, 'message' => 'Not found.']); }

        $state = $this->model->toggle($id);
        ActivityLogger::toggled('voucher', $id, $voucher['code'], $state);
        $this->json(['success' => true, 'message' => 'Status updated.', 'active' => $state]);
    }

    private function validate(int $excludeId = 0): array
    {
        $errors = [];
        $code   = strtoupper(trim(Request::post('code', '')));

        if (!$code)                                  $errors[] = 'Voucher code is required.';
        elseif (!preg_match('/^[A-Z0-9_\-]{3,30}$/', $code)) $errors[] = 'Code must be 3–30 characters (letters, numbers, - _).';
        elseif ($this->model->codeExists($code, $excludeId)) $errors[] = 'This voucher code already exists.';

        $val = Request::float('discount_value');
        if ($val <= 0)                               $errors[] = 'Discount value must be greater than 0.';

        $type = Request::post('discount_type');
        if ($type === 'percentage' && $val > 100)    $errors[] = 'Percentage discount cannot exceed 100%.';

        $start  = Request::post('starts_at');
        $expiry = Request::post('expires_at');
        if (!$start || !$expiry)                     $errors[] = 'Start and expiry dates are required.';
        elseif ($expiry <= $start)                   $errors[] = 'Expiry date must be after start date.';

        return $errors;
    }
}
