<?php

namespace App\Controllers;

use App\Models\ClientModel;
use App\Models\QuotationModel;

class Clients extends BaseController
{
    public function index()
    {
        $search = trim((string) $this->request->getGet("search"));
        $model = new ClientModel();

        if ($search !== "") {
            $model
                ->groupStart()
                ->like("first_name", $search)
                ->orLike("last_name", $search)
                ->orLike("email", $search)
                ->orLike("mobile", $search)
                ->orLike("address", $search)
                ->groupEnd();
        }

        return view("admin/clients/index", [
            "clients" => $model->orderBy("created_at", "DESC")->findAll(250),
            "search" => $search,
            "metrics" => [
                "total" => (new ClientModel())->countAll(),
                "thisMonth" => (new ClientModel())
                    ->where("created_at >=", date("Y-m-01 00:00:00"))
                    ->countAllResults(),
                "complete" => (new ClientModel())
                    ->where("mobile !=", "")
                    ->where("address !=", "")
                    ->countAllResults(),
            ],
        ]);
    }

    public function create()
    {
        if ($this->request->getMethod() === "post") {
            if (!$this->validateClient()) {
                return redirect()
                    ->back()
                    ->withInput()
                    ->with(
                        "error",
                        implode(" ", $this->validator->getErrors()),
                    );
            }

            $data = $this->clientData();
            if ($this->emailExists($data["email"])) {
                return redirect()
                    ->back()
                    ->withInput()
                    ->with(
                        "error",
                        "A client with this email address already exists.",
                    );
            }

            $id = (new ClientModel())->insert($data);
            return redirect()
                ->to(base_url("admin/clients/" . $id))
                ->with("success", "Client created successfully.");
        }

        return view("admin/clients/form", [
            "client" => null,
            "mode" => "create",
        ]);
    }

    public function show($id)
    {
        $client = $this->findClient((int) $id);
        if (!$client) {
            return $this->notFound();
        }

        return view("admin/clients/show", ["client" => $client]);
    }

    public function edit($id)
    {
        $client = $this->findClient((int) $id);
        if (!$client) {
            return $this->notFound();
        }

        if ($this->request->getMethod() === "post") {
            if (!$this->validateClient()) {
                return redirect()
                    ->back()
                    ->withInput()
                    ->with(
                        "error",
                        implode(" ", $this->validator->getErrors()),
                    );
            }

            $data = $this->clientData();
            if ($this->emailExists($data["email"], (int) $id)) {
                return redirect()
                    ->back()
                    ->withInput()
                    ->with(
                        "error",
                        "A client with this email address already exists.",
                    );
            }

            (new ClientModel())->update((int) $id, $data);
            return redirect()
                ->to(base_url("admin/clients/" . $id))
                ->with("success", "Client details updated.");
        }

        return view("admin/clients/form", [
            "client" => $client,
            "mode" => "edit",
        ]);
    }

    public function delete($id)
    {
        $client = $this->findClient((int) $id);
        if (!$client) {
            return $this->notFound();
        }
        if (
            (new QuotationModel())
                ->where("client_id", (int) $id)
                ->countAllResults() > 0
        ) {
            return redirect()
                ->to(base_url("admin/clients/" . $id))
                ->with(
                    "error",
                    "This client has quotations and cannot be deleted.",
                );
        }

        (new ClientModel())->delete((int) $id);
        return redirect()
            ->to(base_url("admin/clients"))
            ->with(
                "success",
                $client["first_name"] .
                    " " .
                    $client["last_name"] .
                    " was deleted.",
            );
    }

    private function validateClient(): bool
    {
        return $this->validate([
            "first_name" => "required|max_length[100]",
            "last_name" => "required|max_length[100]",
            "email" => "required|valid_email|max_length[190]",
            "mobile" => "required|min_length[7]|max_length[40]",
            "address" => "required|max_length[2000]",
        ]);
    }

    private function clientData(): array
    {
        return [
            "first_name" => trim(
                (string) $this->request->getPost("first_name"),
            ),
            "last_name" => trim((string) $this->request->getPost("last_name")),
            "email" => strtolower(
                trim((string) $this->request->getPost("email")),
            ),
            "mobile" => trim((string) $this->request->getPost("mobile")),
            "address" => trim((string) $this->request->getPost("address")),
        ];
    }

    private function emailExists(string $email, ?int $exceptId = null): bool
    {
        $model = new ClientModel();
        $model->where("email", $email);
        if ($exceptId !== null) {
            $model->where("id !=", $exceptId);
        }

        return $model->countAllResults() > 0;
    }

    private function findClient(int $id): ?array
    {
        return (new ClientModel())->find($id);
    }

    private function notFound()
    {
        return redirect()
            ->to(base_url("admin/clients"))
            ->with("error", "Client not found.");
    }
}
