<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\BaseController;
use App\Core\Request;
use App\Core\Response;
use App\Helpers\AjaxResponse;
use App\Helpers\Paginator;
use App\Models\ApiKeyModel;
use App\Models\CustomerModel;
use App\Models\LeadModel;
use App\Services\ActivityLogger;

/**
 * ExternalApiController
 *
 * The actual "external API" behind the API Keys admin page and
 * `docs/API.md` — every route here is authenticated by
 * ApiKeyAuthMiddleware (Authorization: Bearer sk_live_...), not the
 * session cookie the rest of the app uses, since a third-party
 * integration has no browser session. Deliberately small and
 * read-mostly (list/show leads and customers, create a lead) rather
 * than exposing the entire CRM surface — a real external API grows by
 * adding one more explicit, scoped endpoint at a time, not by
 * generically proxying every internal model.
 */
final class ExternalApiController extends BaseController
{
    public function leadsIndex(Request $request): Response
    {
        if (!$this->authorizeScope($request, 'leads.read')) {
            return AjaxResponse::error('This API key does not have the leads.read scope.', 403);
        }

        $model = new LeadModel();
        $paginator = Paginator::fromRequest($request, defaultPerPage: 25);
        $rows = $model->paginate(where: array_filter(['business_line_id' => $request->query('business_line_id')]), paginator: $paginator);

        return AjaxResponse::success(['data' => $rows, 'meta' => $paginator->meta()]);
    }

    public function leadsShow(Request $request, array $params): Response
    {
        if (!$this->authorizeScope($request, 'leads.read')) {
            return AjaxResponse::error('This API key does not have the leads.read scope.', 403);
        }

        $lead = (new LeadModel())->find((int) $params['id']);

        return $lead === null ? AjaxResponse::notFound('Lead not found.') : AjaxResponse::success($lead);
    }

    public function leadsStore(Request $request): Response
    {
        if (!$this->authorizeScope($request, 'leads.write')) {
            return AjaxResponse::error('This API key does not have the leads.write scope.', 403);
        }

        $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',
            'lead_stage_id' => 'required|integer|exists:lead_stages,id',
        ]);
        $data['currency'] = 'CAD';

        $model = new LeadModel();
        $id = $model->insert($data);
        ActivityLogger::record('lead', $id, 'lead_created', 'Lead created via external API', category: 'system');

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

    public function customersIndex(Request $request): Response
    {
        if (!$this->authorizeScope($request, 'customers.read')) {
            return AjaxResponse::error('This API key does not have the customers.read scope.', 403);
        }

        $model = new CustomerModel();
        $paginator = Paginator::fromRequest($request, defaultPerPage: 25);
        $rows = $model->paginate(where: array_filter(['business_line_id' => $request->query('business_line_id')]), paginator: $paginator);

        return AjaxResponse::success(['data' => $rows, 'meta' => $paginator->meta()]);
    }

    public function customersShow(Request $request, array $params): Response
    {
        if (!$this->authorizeScope($request, 'customers.read')) {
            return AjaxResponse::error('This API key does not have the customers.read scope.', 403);
        }

        $customer = (new CustomerModel())->find((int) $params['id']);

        return $customer === null ? AjaxResponse::notFound('Customer not found.') : AjaxResponse::success($customer);
    }

    private function authorizeScope(Request $request, string $scope): bool
    {
        $keyRow = $request->getAttribute('_api_key');

        return is_array($keyRow) && (new ApiKeyModel())->hasScope($keyRow, $scope);
    }
}
