<?php
declare(strict_types=1);

namespace Celena\Module\Cities;

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;

/**
 * Города — справочник для модулей региональной доставки, контактов,
 * многогородовой версии сайта. Один город может быть помечен как is_default
 * (выбирается, если посетитель ещё не указал свой).
 */
final class CitiesController extends AdminController
{
    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 ($deny = $this->deny('cities.manage')) return $deny;
        $page = Filter::int($request->query('page', 1), 1);
        $search = trim((string) $request->query('q', ''));

        $countQ = $this->conn->builder('celena_cities');
        $listQ  = $this->conn->builder('celena_cities');
        if ($search !== '') {
            $like = '%' . mb_strtolower($search, 'UTF-8') . '%';
            $countQ->whereRaw('LOWER(' . $this->conn->quoteId('title') . ') LIKE ?', [$like]);
            $listQ->whereRaw('LOWER(' . $this->conn->quoteId('title') . ') LIKE ?', [$like]);
        }
        $total = $countQ->count();
        $p = new Pagination($page, 25, $total);

        $rows = $listQ
            ->orderBy('sort_order', 'asc')
            ->orderBy('title', 'asc')
            ->limit($p->perPage)->offset($p->offset)
            ->get();

        return $this->view('admin/cities/index', [
            'cities'    => $rows,
            'pagination'=> $p->toArray('/admin/cities?page=:page' . ($search !== '' ? '&q=' . rawurlencode($search) : '')),
            'q'         => $search,
            'total'     => $total,
        ], 'cities', 'Города');
    }

    public function create(Request $request): Response
    {
        if ($deny = $this->deny('cities.manage')) return $deny;
        return $this->view('admin/cities/form', [
            'row' => $this->emptyRow(),
            'form_action' => '/admin/cities/create',
        ], 'cities', 'Новый город');
    }

    public function store(Request $request): Response
    {
        if ($deny = $this->deny('cities.manage')) return $deny;
        if (!Csrf::validate((string) $request->input('_csrf'))) {
            return $this->redirect('/admin/cities/create', 'CSRF.', 'error');
        }
        $data = $this->extract($request);
        if ($data['title'] === '') {
            return $this->redirect('/admin/cities/create', 'Название обязательно.', 'error');
        }
        if ($data['slug'] === '') $data['slug'] = Filter::slug($data['title']);
        if ($this->slugExists($data['slug'])) {
            return $this->redirect('/admin/cities/create', 'Slug занят.', 'error');
        }
        if (!empty($data['is_default'])) {
            $this->conn->builder('celena_cities')->update(['is_default' => false]);
        }
        $now = date('Y-m-d H:i:s');
        $data['created_at'] = $now;
        $data['updated_at'] = $now;
        $this->conn->builder('celena_cities')->insert($data);
        return $this->redirect('/admin/cities', 'Город добавлен.');
    }

    public function edit(Request $request, array $params): Response
    {
        if ($deny = $this->deny('cities.manage')) return $deny;
        $id = Filter::int($params['id'] ?? 0);
        $row = $this->conn->builder('celena_cities')->where('id', '=', $id)->first();
        if ($row === null) return $this->redirect('/admin/cities', 'Не найден.', 'error');
        return $this->view('admin/cities/form', [
            'row' => $row,
            'form_action' => '/admin/cities/' . $id . '/update',
        ], 'cities', 'Город: ' . $row['title']);
    }

    public function update(Request $request, array $params): Response
    {
        if ($deny = $this->deny('cities.manage')) return $deny;
        if (!Csrf::validate((string) $request->input('_csrf'))) {
            return $this->redirect('/admin/cities', 'CSRF.', 'error');
        }
        $id = Filter::int($params['id'] ?? 0);
        $existing = $this->conn->builder('celena_cities')->where('id', '=', $id)->first();
        if ($existing === null) return $this->redirect('/admin/cities', 'Не найден.', 'error');
        $data = $this->extract($request);
        if ($data['slug'] === '') $data['slug'] = Filter::slug($data['title']);
        if ($data['slug'] !== $existing['slug'] && $this->slugExists($data['slug'])) {
            return $this->redirect('/admin/cities/' . $id . '/edit', 'Slug занят.', 'error');
        }
        if (!empty($data['is_default'])) {
            $this->conn->builder('celena_cities')->update(['is_default' => false]);
        }
        $data['updated_at'] = date('Y-m-d H:i:s');
        $this->conn->builder('celena_cities')->where('id', '=', $id)->update($data);
        return $this->redirect('/admin/cities', 'Сохранено.');
    }

    public function delete(Request $request, array $params): Response
    {
        if ($deny = $this->deny('cities.manage')) return $deny;
        if (!Csrf::validate((string) $request->input('_csrf'))) {
            return $this->redirect('/admin/cities', 'CSRF.', 'error');
        }
        $id = Filter::int($params['id'] ?? 0);
        $this->conn->builder('celena_cities')->where('id', '=', $id)->delete();
        return $this->redirect('/admin/cities', 'Удалён.');
    }

    private function emptyRow(): array
    {
        return [
            'id' => 0,
            'slug' => '',
            'title' => 'Одесса',
            'country' => 'Украина',
            'region' => 'Одесская область',
            'timezone' => 'Europe/Kyiv',
            'phone' => '+380 48',
            'latitude' => '46.482526',
            'longitude' => '30.723309',
            'is_default' => false,
            'is_active' => true,
            'sort_order' => 0,
        ];
    }

    private function extract(Request $request): array
    {
        $lat = (string) $request->input('latitude', '');
        $lng = (string) $request->input('longitude', '');
        return [
            'title'      => Filter::string($request->input('title'), 200),
            'slug'       => Filter::urlSlug($request->input('slug', '')),
            'country'    => Filter::string($request->input('country'), 100),
            'region'     => Filter::string($request->input('region'), 200),
            'timezone'   => Filter::string($request->input('timezone'), 64),
            'phone'      => Filter::string($request->input('phone'), 32),
            'latitude'   => $lat === '' ? null : (float) $lat,
            'longitude'  => $lng === '' ? null : (float) $lng,
            'is_default' => Filter::bool($request->input('is_default')),
            'is_active'  => Filter::bool($request->input('is_active')),
            'sort_order' => Filter::int($request->input('sort_order'), 0),
        ];
    }

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