<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Session;
use App\Core\Tenant;
use App\Models\Branch;
use App\Models\CashBox;
use App\Models\Company;
use App\Models\User;
use App\Services\AuditService;

class BranchController extends Controller
{
    public function index(Request $request): void
    {
        $companyId = (int) Tenant::companyId();
        if ($companyId <= 0) {
            flash('error', 'Selecciona una empresa antes de gestionar sucursales.');
            redirect('empresas/seleccionar');
        }

        $branchModel = new Branch();
        $branches = $branchModel->listByCompany($companyId);
        $branchLimit = $branchModel->currentPlanLimit($companyId);
        $branchCount = count($branches);
        $branchCanCreate = true;
        if (is_array($branchLimit)) {
            $branchCanCreate = $branchCount < (int) ($branchLimit['max_sucursales'] ?? 0);
        }

        $this->render('sucursales/index', [
            'title' => 'Sucursales',
            'branches' => $branches,
            'countries' => (new Company())->countries(),
            'cities' => (new Company())->cities(),
            'users' => (new User())->assignableByCompany($companyId),
            'cashBoxes' => (new CashBox())->listByCompany($companyId),
            'branch_limit' => $branchLimit,
            'branch_count' => $branchCount,
            'branch_can_create' => $branchCanCreate,
        ]);
    }

    public function store(Request $request): never
    {
        $companyId = (int) Tenant::companyId();
        if ($companyId <= 0) {
            flash('error', 'Selecciona una empresa antes de crear sucursales.');
            redirect('empresas/seleccionar');
        }

        Session::setOldInput($request->all());

        $name = trim((string) $request->input('nombre', ''));
        $code = trim((string) $request->input('codigo', ''));
        $countryId = (int) $request->input('pais_id', 0);
        $cityId = (int) $request->input('ciudad_id', 0);
        $active = (int) $request->input('activa', 1) === 1 ? 1 : 0;
        $countryId = $countryId > 0 ? $countryId : null;

        if ($name === '') {
            flash('error', 'El nombre de la sucursal es obligatorio.');
            redirect('sucursales');
        }

        if ($cityId > 0 && $countryId === null) {
            flash('error', 'Selecciona un pais antes de elegir una ciudad.');
            redirect('sucursales');
        }

        $companyModel = new Company();
        if ($cityId > 0 && $countryId !== null && !$companyModel->cityBelongsToCountry($cityId, $countryId)) {
            flash('error', 'La ciudad seleccionada no pertenece al pais indicado.');
            redirect('sucursales');
        }

        $branchModel = new Branch();
        if ($code !== '' && $branchModel->existsCode($companyId, $code)) {
            flash('error', 'Ya existe una sucursal con ese código.');
            redirect('sucursales');
        }

        $branchLimit = $branchModel->currentPlanLimit($companyId);
        if (is_array($branchLimit)) {
            $maxBranches = (int) ($branchLimit['max_sucursales'] ?? 0);
            $currentBranches = $branchModel->countByCompany($companyId);
            if ($currentBranches >= $maxBranches) {
                $planName = trim((string) ($branchLimit['plan_nombre'] ?? 'plan actual'));
                if ($maxBranches <= 0) {
                    flash(
                        'error',
                        'Tu plan ' . $planName . ' no permite crear sucursales. Actualiza el plan para habilitar esta función.'
                    );
                    redirect('sucursales');
                }

                flash(
                    'error',
                    'Límite alcanzado: tu plan ' . $planName . ' permite hasta ' . $maxBranches .
                    ' sucursal' . ($maxBranches === 1 ? '' : 'es') . '.'
                );
                redirect('sucursales');
            }
        }

        try {
            $branchId = $branchModel->create([
                'empresa_id' => $companyId,
                'nombre' => $name,
                'codigo' => $code !== '' ? $code : null,
                'telefono' => trim((string) $request->input('telefono', '')) ?: null,
                'direccion' => trim((string) $request->input('direccion', '')) ?: null,
                'ciudad_id' => $cityId > 0 ? $cityId : null,
                'activa' => $active,
                'created_at' => date('Y-m-d H:i:s'),
                'updated_at' => date('Y-m-d H:i:s'),
            ]);

            Session::clearOldInput();
            AuditService::track('sucursales.crear', 'Sucursal creada ID: ' . $branchId);
            flash('success', 'Sucursal creada correctamente.');
            redirect('sucursales');
        } catch (\Throwable $e) {
            flash('error', 'No fue posible crear la sucursal: ' . $e->getMessage());
            redirect('sucursales');
        }
    }

    public function update(Request $request): never
    {
        $companyId = (int) Tenant::companyId();
        $branchId = (int) $request->param('id', 0);

        if ($companyId <= 0 || $branchId <= 0) {
            flash('error', 'No fue posible actualizar la sucursal.');
            redirect('sucursales');
        }

        $branchModel = new Branch();
        $branch = $branchModel->findById($branchId, $companyId);
        if ($branch === null) {
            flash('error', 'Sucursal no encontrada.');
            redirect('sucursales');
        }

        $name = trim((string) $request->input('nombre', ''));
        $code = trim((string) $request->input('codigo', ''));
        $countryId = (int) $request->input('pais_id', 0);
        $cityId = (int) $request->input('ciudad_id', 0);
        $countryId = $countryId > 0 ? $countryId : null;

        if ($name === '') {
            flash('error', 'El nombre de la sucursal es obligatorio.');
            redirect('sucursales');
        }

        if ($cityId > 0 && $countryId === null) {
            flash('error', 'Selecciona un pais antes de elegir una ciudad.');
            redirect('sucursales');
        }

        $companyModel = new Company();
        if ($cityId > 0 && $countryId !== null && !$companyModel->cityBelongsToCountry($cityId, $countryId)) {
            flash('error', 'La ciudad seleccionada no pertenece al pais indicado.');
            redirect('sucursales');
        }

        if ($code !== '' && $branchModel->existsCode($companyId, $code, $branchId)) {
            flash('error', 'Ya existe otra sucursal con ese código.');
            redirect('sucursales');
        }

        try {
            $branchModel->updateById($branchId, [
                'nombre' => $name,
                'codigo' => $code !== '' ? $code : null,
                'telefono' => trim((string) $request->input('telefono', '')) ?: null,
                'direccion' => trim((string) $request->input('direccion', '')) ?: null,
                'ciudad_id' => $cityId > 0 ? $cityId : null,
                'updated_at' => date('Y-m-d H:i:s'),
            ], $companyId);

            AuditService::track('sucursales.actualizar', 'Sucursal actualizada ID: ' . $branchId);
            flash('success', 'Sucursal actualizada.');
            redirect('sucursales');
        } catch (\Throwable $e) {
            flash('error', 'No fue posible actualizar la sucursal: ' . $e->getMessage());
            redirect('sucursales');
        }
    }

    public function toggle(Request $request): never
    {
        $companyId = (int) Tenant::companyId();
        $branchId = (int) $request->param('id', 0);
        $newState = (int) $request->input('activa', 0) === 1 ? 1 : 0;

        if ($companyId <= 0 || $branchId <= 0) {
            flash('error', 'No fue posible cambiar estado de la sucursal.');
            redirect('sucursales');
        }

        $branchModel = new Branch();
        $branch = $branchModel->findById($branchId, $companyId);
        if ($branch === null) {
            flash('error', 'Sucursal no encontrada.');
            redirect('sucursales');
        }

        try {
            $branchModel->updateById($branchId, [
                'activa' => $newState,
                'updated_at' => date('Y-m-d H:i:s'),
            ], $companyId);

            AuditService::track(
                'sucursales.estado',
                'Sucursal ID: ' . $branchId . ' cambiada a ' . ($newState === 1 ? 'activa' : 'inactiva')
            );
            flash('success', 'Estado de sucursal actualizado.');
            redirect('sucursales');
        } catch (\Throwable $e) {
            flash('error', 'No fue posible cambiar estado de la sucursal: ' . $e->getMessage());
            redirect('sucursales');
        }
    }

    public function assignUser(Request $request): never
    {
        $companyId = (int) Tenant::companyId();
        $branchId = (int) $request->param('id', 0);
        $userId = (int) $request->input('usuario_id', 0);

        if ($companyId <= 0 || $branchId <= 0 || $userId <= 0) {
            flash('error', 'No fue posible asignar el usuario a la sucursal.');
            redirect('sucursales');
        }

        $branchModel = new Branch();
        if ($branchModel->findById($branchId, $companyId) === null) {
            flash('error', 'Sucursal no encontrada.');
            redirect('sucursales');
        }

        $userModel = new User();
        if (!$userModel->belongsToCompany($companyId, $userId)) {
            flash('error', 'El usuario no pertenece a la empresa actual.');
            redirect('sucursales');
        }

        try {
            $userModel->updateById($userId, ['sucursal_id' => $branchId], $companyId);
            AuditService::track('sucursales.usuario.asignar', 'Usuario ID: ' . $userId . ' asignado a sucursal ID: ' . $branchId);
            flash('success', 'Usuario asignado correctamente.');
            redirect('sucursales');
        } catch (\Throwable $e) {
            flash('error', 'No fue posible asignar el usuario: ' . $e->getMessage());
            redirect('sucursales');
        }
    }

    public function unassignUser(Request $request): never
    {
        $companyId = (int) Tenant::companyId();
        $branchId = (int) $request->param('id', 0);
        $userId = (int) $request->param('userId', 0);

        if ($companyId <= 0 || $branchId <= 0 || $userId <= 0) {
            flash('error', 'No fue posible quitar el usuario de la sucursal.');
            redirect('sucursales');
        }

        $userModel = new User();
        $user = $userModel->findById($userId, $companyId);
        if ($user === null) {
            flash('error', 'Usuario no encontrado.');
            redirect('sucursales');
        }

        if ((int) ($user['sucursal_id'] ?? 0) !== $branchId) {
            flash('error', 'El usuario no está asignado a esa sucursal.');
            redirect('sucursales');
        }

        try {
            $userModel->updateById($userId, ['sucursal_id' => null], $companyId);
            AuditService::track('sucursales.usuario.quitar', 'Usuario ID: ' . $userId . ' removido de sucursal ID: ' . $branchId);
            flash('success', 'Usuario removido de la sucursal.');
            redirect('sucursales');
        } catch (\Throwable $e) {
            flash('error', 'No fue posible quitar el usuario: ' . $e->getMessage());
            redirect('sucursales');
        }
    }

    public function storeCashBox(Request $request): never
    {
        $companyId = (int) Tenant::companyId();
        $branchId = (int) $request->param('id', 0);
        $name = trim((string) $request->input('nombre', ''));
        $state = (int) $request->input('activa', 1) === 1 ? 'activa' : 'inactiva';

        if ($companyId <= 0 || $branchId <= 0) {
            flash('error', 'No fue posible crear la caja.');
            redirect('sucursales');
        }

        if ($name === '') {
            flash('error', 'El nombre de la caja es obligatorio.');
            redirect('sucursales');
        }

        $branchModel = new Branch();
        if ($branchModel->findById($branchId, $companyId) === null) {
            flash('error', 'Sucursal no encontrada.');
            redirect('sucursales');
        }

        $cashBoxModel = new CashBox();
        if ($cashBoxModel->existsName($companyId, $branchId, $name)) {
            flash('error', 'Ya existe una caja con ese nombre en la sucursal.');
            redirect('sucursales');
        }

        try {
            $cashBoxId = $cashBoxModel->create([
                'empresa_id' => $companyId,
                'sucursal_id' => $branchId,
                'nombre' => $name,
                'estado' => $state,
                'created_at' => date('Y-m-d H:i:s'),
            ]);

            AuditService::track('sucursales.caja.crear', 'Caja creada ID: ' . $cashBoxId . ' en sucursal ID: ' . $branchId);
            flash('success', 'Caja creada correctamente.');
            redirect('sucursales');
        } catch (\Throwable $e) {
            flash('error', 'No fue posible crear la caja: ' . $e->getMessage());
            redirect('sucursales');
        }
    }

    public function toggleCashBox(Request $request): never
    {
        $companyId = (int) Tenant::companyId();
        $cashBoxId = (int) $request->param('id', 0);
        $newState = (int) $request->input('activa', 0) === 1 ? 'activa' : 'inactiva';

        if ($companyId <= 0 || $cashBoxId <= 0) {
            flash('error', 'No fue posible cambiar el estado de la caja.');
            redirect('sucursales');
        }

        $cashBoxModel = new CashBox();
        $cashBox = $cashBoxModel->findByIdAndCompany($companyId, $cashBoxId);
        if ($cashBox === null) {
            flash('error', 'Caja no encontrada para la empresa actual.');
            redirect('sucursales');
        }

        try {
            $cashBoxModel->updateById($cashBoxId, ['estado' => $newState], $companyId);
            AuditService::track('sucursales.caja.estado', 'Caja ID: ' . $cashBoxId . ' cambiada a ' . $newState);
            flash('success', 'Estado de caja actualizado.');
            redirect('sucursales');
        } catch (\Throwable $e) {
            flash('error', 'No fue posible actualizar la caja: ' . $e->getMessage());
            redirect('sucursales');
        }
    }
}
