<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Repositories\TerritoryRepository;
use Core\Controller;
use Core\Pagination;
use Core\Request;
use Core\Response;
use Core\Validator;

class TerritoryController extends Controller
{
    public function index(): Response
    {
        if ($redirect = $this->requireAuth()) {
            return $redirect;
        }

        $request     = Request::capture();
        $search      = (string) ($request->input('search') ?? '');
        $page        = max(1, (int) ($request->input('page') ?? 1));
        $perPage     = 20;
        $repo        = new TerritoryRepository(database());
        $total       = $repo->countAll($search);
        $pagination  = new Pagination($total, $page, $perPage);
        $territories = $repo->findPaged($page, $perPage, $search);
        $counts      = $repo->householdCountsKeyed();

        return $this->view('territories.index', [
            'pageTitle'   => 'Territories',
            'territories' => $territories,
            'counts'      => $counts,
            'search'      => $search,
            'pagination'  => $pagination,
        ]);
    }

    public function show(int|string $id): Response
    {
        if ($redirect = $this->requireAuth()) {
            return $redirect;
        }

        $repo      = new TerritoryRepository(database());
        $territory = $repo->find((int) $id);

        if (!$territory) {
            return Response::notFound('Territory not found.');
        }

        $streets = $repo->distinctStreets((int) $id);

        $householdRepo = new \App\Repositories\HouseholdRepository(database());
        $households    = $householdRepo->findAllByTerritory((int) $id);

        return $this->view('territories.show', [
            'pageTitle'   => e($territory['name']),
            'territory'   => $territory,
            'streets'     => $streets,
            'households'  => $households,
        ]);
    }

    public function create(): Response
    {
        if ($redirect = $this->requireAuth()) {
            return $redirect;
        }

        return $this->view('territories.create', [
            'pageTitle' => 'New Territory',
            'errors'    => [],
            'old'       => [],
        ]);
    }

    public function store(): Response
    {
        if ($redirect = $this->requireAuth()) {
            return $redirect;
        }

        $request = Request::capture();

        if (!verify_csrf_token($request->input('_token'))) {
            return $this->view('territories.create', [
                'pageTitle' => 'New Territory',
                'errors'    => ['_token' => ['Invalid request. Please try again.']],
                'old'       => $request->all(),
            ]);
        }

        $name        = trim((string) ($request->input('name') ?? ''));
        $description = trim((string) ($request->input('description') ?? ''));
        $coordinates = trim((string) ($request->input('coordinates') ?? ''));

        $validator = (new Validator())
            ->required('name', $name, 'Name is required.')
            ->maxLength('name', $name, 255);

        if ($validator->fails()) {
            return $this->view('territories.create', [
                'pageTitle' => 'New Territory',
                'errors'    => $validator->errors(),
                'old'       => $request->all(),
            ]);
        }

        $now = date('Y-m-d H:i:s');
        database()->execute(
            'INSERT INTO territories (name, description, coordinates, created_at, updated_at)
             VALUES (:name, :description, :coordinates, :now, :now)',
            ['name' => $name, 'description' => $description, 'coordinates' => $coordinates, 'now' => $now]
        );

        flash('success', "Territory \"{$name}\" created.");
        return $this->redirect('/territories');
    }

    public function edit(int|string $id): Response
    {
        if ($redirect = $this->requireAuth()) {
            return $redirect;
        }

        $territory = (new TerritoryRepository(database()))->find((int) $id);

        if (!$territory) {
            return Response::notFound('Territory not found.');
        }

        return $this->view('territories.edit', [
            'pageTitle' => 'Edit Territory',
            'territory' => $territory,
            'errors'    => [],
        ]);
    }

    public function update(int|string $id): Response
    {
        if ($redirect = $this->requireAuth()) {
            return $redirect;
        }

        $request   = Request::capture();
        $repo      = new TerritoryRepository(database());
        $territory = $repo->find((int) $id);

        if (!$territory) {
            return Response::notFound('Territory not found.');
        }

        if (!verify_csrf_token($request->input('_token'))) {
            return $this->view('territories.edit', [
                'pageTitle' => 'Edit Territory',
                'territory' => $territory,
                'errors'    => ['_token' => ['Invalid request. Please try again.']],
            ]);
        }

        $name        = trim((string) ($request->input('name') ?? ''));
        $description = trim((string) ($request->input('description') ?? ''));
        $coordinates = trim((string) ($request->input('coordinates') ?? ''));

        $validator = (new Validator())
            ->required('name', $name, 'Name is required.')
            ->maxLength('name', $name, 255);

        if ($validator->fails()) {
            return $this->view('territories.edit', [
                'pageTitle' => 'Edit Territory',
                'territory' => array_merge($territory, ['name' => $name, 'description' => $description, 'coordinates' => $coordinates]),
                'errors'    => $validator->errors(),
            ]);
        }

        database()->execute(
            'UPDATE territories SET name = :name, description = :description, coordinates = :coordinates,
             updated_at = :now WHERE id = :id',
            ['name' => $name, 'description' => $description, 'coordinates' => $coordinates,
             'now' => date('Y-m-d H:i:s'), 'id' => $id]
        );

        flash('success', "Territory \"{$name}\" updated.");
        return $this->redirect('/territories/' . $id);
    }

    public function delete(int|string $id): Response
    {
        if ($redirect = $this->requireAuth()) {
            return $redirect;
        }

        $request   = Request::capture();
        $territory = (new TerritoryRepository(database()))->find((int) $id);

        if (!$territory) {
            return Response::notFound('Territory not found.');
        }

        if (!verify_csrf_token($request->input('_token'))) {
            flash('error', 'Invalid request.');
            return $this->redirect('/territories');
        }

        database()->execute('DELETE FROM territories WHERE id = :id', ['id' => $id]);

        flash('success', 'Territory deleted.');
        return $this->redirect('/territories');
    }
}
