<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\BaseController;
use App\Core\Database;
use App\Core\Request;
use App\Core\Response;
use App\Helpers\AjaxResponse;
use App\Helpers\Paginator;
use App\Models\AppointmentModel;
use App\Models\AttachmentModel;
use App\Models\CommentModel;
use App\Models\CustomerModel;
use App\Models\NoteModel;
use App\Models\TagModel;
use App\Services\ActivityLogger;
use App\Services\ExportService;

final class CustomerController extends BaseController
{
    public function index(Request $request): Response
    {
        $model = new CustomerModel();
        $paginator = Paginator::fromRequest($request, defaultPerPage: 20);

        $filters = [
            'search' => $request->query('search'),
            'business_line_id' => $request->query('business_line_id'),
            'status' => $request->query('status'),
        ];

        $rows = $model->paginatedList($filters, $paginator);

        if ($request->isAjax() || $request->isJson()) {
            return AjaxResponse::success(['rows' => $rows, 'meta' => $paginator->meta()]);
        }

        return $this->view('customers/index', [
            'title' => 'Customers',
            'activeNav' => 'customers',
            'breadcrumbs' => [['Home', 'dashboard'], ['CRM', 'customers'], ['Customers', 'customers']],
            'rows' => $rows,
            'meta' => $paginator->meta(),
            'lookups' => $this->lookups(),
        ]);
    }

    public function show(Request $request, array $params): Response
    {
        $id = (int) $params['id'];
        $model = new CustomerModel();
        $customer = $model->findWithRelations($id);

        if ($customer === null) {
            return Response::html('404 Not Found', 404);
        }

        if ($request->isAjax() || $request->isJson()) {
            return AjaxResponse::success($customer);
        }

        return $this->view('customers/show', [
            'title' => trim($customer['first_name'] . ' ' . ($customer['last_name'] ?? '')),
            'activeNav' => 'customers',
            'breadcrumbs' => [['Home', 'dashboard'], ['Customers', 'customers'], ['Customer Details', 'customers/' . $id]],
            'customer' => $customer,
            'entityType' => 'customer',
            'entityId' => $id,
            'timeline' => ActivityLogger::timelineFor('customer', $id),
            'appointments' => (new AppointmentModel())->historyFor('customer', $id),
            'notes' => (new NoteModel())->forEntity('customer', $id),
            'comments' => (new CommentModel())->forEntity('customer', $id),
            'attachments' => (new AttachmentModel())->forEntity('customer', $id),
            'tags' => (new TagModel())->forEntity('customer', $id),
            'emails' => (new \App\Models\EmailMessageModel())->forEntity('customer', $id),
            'entityEmail' => $customer['email'],
            'lookups' => $this->lookups(),
        ]);
    }

    public function store(Request $request): Response
    {
        $data = $this->validateOrFail($request, [
            'first_name' => 'required|string|max:100',
            'last_name' => 'nullable|string|max:100',
            'email' => 'nullable|email|max:191',
            'phone' => 'nullable|string|max:30',
            'business_line_id' => 'required|integer|exists:business_lines,id',
            'service_plan_id' => 'nullable|integer|exists:service_plans,id',
            'assigned_staff_id' => 'nullable|integer|exists:users,id',
            'address_line1' => 'nullable|string|max:191',
            'city' => 'nullable|string|max:120',
            'province' => 'nullable|string|max:120',
            'postal_code' => 'nullable|string|max:20',
        ]);

        $data['currency'] = 'CAD';
        $data['status'] = 'active';
        $data['customer_since'] = date('Y-m-d');

        $model = new CustomerModel();
        $id = $model->insert($data, $this->currentUserId());

        ActivityLogger::record('customer', $id, 'customer_created', 'Customer created');
        (new \App\Services\AutomationEngine())->fire('customer_created', 'customer', $id);

        return AjaxResponse::created($model->findWithRelations($id), 'Customer created.');
    }

    public function update(Request $request, array $params): Response
    {
        $data = $this->validateOrFail($request, [
            'first_name' => 'required|string|max:100',
            'last_name' => 'nullable|string|max:100',
            'email' => 'nullable|email|max:191',
            'phone' => 'nullable|string|max:30',
            'company_id' => 'nullable|integer|exists:companies,id',
            'service_plan_id' => 'nullable|integer|exists:service_plans,id',
            'assigned_staff_id' => 'nullable|integer|exists:users,id',
            'status' => 'required|in:active,paused,churned',
            'address_line1' => 'nullable|string|max:191',
            'city' => 'nullable|string|max:120',
            'province' => 'nullable|string|max:120',
            'postal_code' => 'nullable|string|max:20',
        ]);

        $id = (int) $params['id'];
        $model = new CustomerModel();
        $model->update($id, $data, $this->currentUserId());

        ActivityLogger::record('customer', $id, 'customer_updated', 'Customer details updated');

        return AjaxResponse::success($model->findWithRelations($id), 'Customer updated.');
    }

    public function destroy(Request $request, array $params): Response
    {
        $id = (int) $params['id'];
        (new CustomerModel())->delete($id, $this->currentUserId());
        ActivityLogger::record('customer', $id, 'customer_deleted', 'Customer moved to trash');

        return AjaxResponse::success(null, 'Customer moved to trash.');
    }

    public function restore(Request $request, array $params): Response
    {
        $id = (int) $params['id'];
        (new CustomerModel())->restore($id);
        ActivityLogger::record('customer', $id, 'customer_restored', 'Customer restored from trash', category: 'admin');

        return AjaxResponse::success(null, 'Customer restored.');
    }

    public function trashed(Request $request): Response
    {
        $stmt = Database::connection()->prepare(
            "SELECT * FROM customers WHERE deleted_at IS NOT NULL ORDER BY deleted_at DESC LIMIT 100"
        );
        $stmt->execute();

        return AjaxResponse::success($stmt->fetchAll());
    }

    public function export(Request $request): Response
    {
        $filters = [
            'search' => $request->query('search'),
            'business_line_id' => $request->query('business_line_id'),
            'status' => $request->query('status'),
        ];

        $csv = (new ExportService())->exportCustomers($filters);

        return Response::html($csv)
            ->withHeader('Content-Type', 'text/csv; charset=UTF-8')
            ->withHeader('Content-Disposition', 'attachment; filename="customers-' . date('Y-m-d') . '.csv"');
    }

    private function lookups(): array
    {
        $pdo = Database::connection();

        return [
            'business_lines' => $pdo->query('SELECT id, name FROM business_lines ORDER BY name')->fetchAll(),
            'service_plans' => $pdo->query('SELECT id, name FROM service_plans WHERE is_active = 1 ORDER BY name')->fetchAll(),
            'staff' => $pdo->query("SELECT id, CONCAT(first_name, ' ', last_name) AS name FROM users WHERE deleted_at IS NULL AND status = 'active' ORDER BY first_name")->fetchAll(),
            'companies' => (new \App\Models\CompanyModel())->forSelect(),
        ];
    }
}
