<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Models\CategoryModel;
use App\Helpers\ImageUploader;
use App\Helpers\ActivityLogger;
use Core\Request;

final class CategoryController extends BaseController
{
    private CategoryModel $model;
    private ImageUploader $uploader;

    public function __construct()
    {
        parent::__construct();
        $this->model    = new CategoryModel();
        $this->uploader = new ImageUploader('categories');
    }

    // ── List ──────────────────────────────────────────────────────────────────

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

        $page       = $this->currentPage();
        $categories = $this->model->all($page);
        $total      = $this->model->count();

        $this->view('menu.categories.index', [
            'pageTitle'   => 'Categories',
            'breadcrumbs' => ['Categories' => null],
            'categories'  => $categories,
            'total'       => $total,
            'page'        => $page,
        ]);
    }

    // ── Create Form ───────────────────────────────────────────────────────────

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

        $this->view('menu.categories.form', [
            'pageTitle'   => 'Add Category',
            'breadcrumbs' => ['Categories' => url('categories'), 'Add Category' => null],
            'category'    => null,
        ]);
    }

    // ── Store ─────────────────────────────────────────────────────────────────

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

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

        $name     = Request::str('name');
        $slug     = $this->uniqueSlug(slugify($name));
        $iconPath = null;

        $file = Request::file('icon_image');
        if ($file) {
            $result = $this->uploader->upload($file);
            if (!$result['success']) {
                $this->flash('error', $result['error']);
                $this->redirect('/categories/create');
            }
            $iconPath = $result['path'];
        }

        $newId = $this->model->create([
            'name'       => $name,
            'slug'       => $slug,
            'icon_image' => $iconPath,
            'sort_order' => Request::int('sort_order', 0),
            'is_active'  => Request::bool('is_active', true) ? 1 : 0,
            'created_by' => \Core\Auth::id(),
        ]);

        ActivityLogger::created('category', $newId, $name);
        $this->flash('success', "Category <strong>{$name}</strong> created successfully.");
        $this->redirect('/categories');
    }

    // ── Edit Form ─────────────────────────────────────────────────────────────

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

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

        $this->view('menu.categories.form', [
            'pageTitle'   => 'Edit Category',
            'breadcrumbs' => ['Categories' => url('categories'), 'Edit' => null],
            'category'    => $category,
        ]);
    }

    // ── Update ────────────────────────────────────────────────────────────────

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

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

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

        $name     = Request::str('name');
        $slug     = $this->uniqueSlug(slugify($name), $id);
        $iconPath = $category['icon_image'];

        $file = Request::file('icon_image');
        if ($file) {
            $result = $this->uploader->upload($file);
            if (!$result['success']) {
                $this->flash('error', $result['error']);
                $this->redirect("/categories/{$id}/edit");
            }
            if ($iconPath) $this->uploader->delete($iconPath);
            $iconPath = $result['path'];
        }

        if (Request::post('remove_image') === '1' && $iconPath) {
            $this->uploader->delete($iconPath);
            $iconPath = null;
        }

        $this->model->update($id, [
            'name'       => $name,
            'slug'       => $slug,
            'icon_image' => $iconPath,
            'sort_order' => Request::int('sort_order', 0),
            'is_active'  => Request::bool('is_active', true) ? 1 : 0,
        ]);

        ActivityLogger::updated('category', $id, $name);
        $this->flash('success', "Category <strong>{$name}</strong> updated successfully.");
        $this->redirect('/categories');
    }

    // ── Delete ────────────────────────────────────────────────────────────────

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

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

        $itemCount = (int) $this->db->fetchValue(
            "SELECT COUNT(*) FROM menu_items WHERE category_id = ?", [$id]
        );
        if ($itemCount > 0) {
            $this->flash('error', "Cannot delete — this category has {$itemCount} menu item(s). Remove items first.");
            $this->redirect('/categories');
        }

        if ($category['icon_image']) $this->uploader->delete($category['icon_image']);

        $this->model->delete($id);
        ActivityLogger::deleted('category', $id, $category['name']);
        $this->flash('success', 'Category deleted successfully.');
        $this->redirect('/categories');
    }

    // ── Toggle Active (AJAX) ──────────────────────────────────────────────────

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

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

        $cat      = $this->model->find($id);
        $newState = $this->model->toggle($id);
        ActivityLogger::toggled('category', $id, $cat['name'] ?? '', $newState);
        $this->json(['success' => true, 'message' => 'Status updated.', 'active' => $newState]);
    }

    // ── Inline sort update (AJAX, Excel-style) ─────────────────────────────────

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

        $id = (int)$params['id'];
        if (!$this->model->find($id)) {
            $this->json(['success' => false, 'message' => 'Category not found.']);
        }
        $sort = max(0, Request::int('sort_order', 0));
        $this->db->update('categories', ['sort_order' => $sort], ['id' => $id]);
        $this->json(['success' => true, 'sort_order' => $sort]);
    }

    // ── Internals ─────────────────────────────────────────────────────────────

    /** @return string[] */
    private function validate(int $excludeId = 0): array
    {
        $errors = [];
        $name   = Request::str('name');

        if (!$name) {
            $errors[] = 'Category name is required.';
        } elseif (mb_strlen($name) > 100) {
            $errors[] = 'Category name must not exceed 100 characters.';
        }

        if ($name && $this->model->slugExists(slugify($name), $excludeId)) {
            $errors[] = 'A category with this name already exists.';
        }

        return $errors;
    }

    private function uniqueSlug(string $slug, int $excludeId = 0): string
    {
        $original = $slug;
        $i        = 1;
        while ($this->model->slugExists($slug, $excludeId)) {
            $slug = $original . '-' . $i++;
        }
        return $slug;
    }
}
