<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\BaseController;
use App\Core\Request;
use App\Core\Response;
use App\Core\Session;
use App\Helpers\AjaxResponse;
use App\Models\IntegrationModel;
use App\Services\ActivityLogger;
use App\Services\GoogleOAuthService;
use App\Services\MetaIntegrationService;

/**
 * IntegrationController
 *
 * One controller for every provider in the brief (OpenAI, ElevenLabs,
 * Twilio, WhatsApp, Google Calendar, Google OAuth, Facebook, Instagram,
 * TikTok, Meta Pixel, Google Analytics) because they all reduce to the
 * same three operations against the generic `integrations` table:
 * connect() (store encrypted credentials), disconnect(), and — for the
 * OAuth-based ones — a redirect-out/callback-in pair. Provider-specific
 * behavior (webhook signature checks, TwiML, tool calling) lives in
 * each provider's own service class; this controller is purely CRUD +
 * OAuth plumbing.
 */
final class IntegrationController extends BaseController
{
    private const API_KEY_PROVIDERS = ['openai', 'elevenlabs', 'twilio', 'whatsapp', 'meta_pixel', 'google_analytics'];
    private const GOOGLE_OAUTH_PROVIDERS = ['google_oauth', 'google_calendar'];

    public function index(Request $request): Response
    {
        $rows = (new IntegrationModel())->all();

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

        return $this->view('ai/integrations', [
            'title' => 'Integrations',
            'activeNav' => 'integrations',
            'breadcrumbs' => [['Home', 'dashboard'], ['AI', 'ai-assistant'], ['Integrations', 'integrations']],
            'rows' => $rows,
        ]);
    }

    /** Direct API-key style connect (OpenAI, ElevenLabs, Twilio, WhatsApp, Meta Pixel, Google Analytics). */
    public function connect(Request $request, array $params): Response
    {
        $slug = $params['slug'];

        if (!in_array($slug, self::API_KEY_PROVIDERS, true)) {
            return AjaxResponse::error('This integration must be connected via OAuth — use the Connect button instead.', 422);
        }

        $credentials = $request->input('credentials', []);
        if (!is_array($credentials) || $credentials === []) {
            return AjaxResponse::error('At least one credential field is required.', 422);
        }

        (new IntegrationModel())->connect($slug, $credentials, $this->currentUserId());
        ActivityLogger::logAction("Connected integration: {$slug}", 'admin');

        return AjaxResponse::success(null, 'Integration connected.');
    }

    public function disconnect(Request $request, array $params): Response
    {
        $slug = $params['slug'];
        (new IntegrationModel())->disconnect($slug);
        ActivityLogger::logAction("Disconnected integration: {$slug}", 'admin');

        return AjaxResponse::success(null, 'Integration disconnected.');
    }

    /** Saves the Client ID/Secret an OAuth integration needs before the "Connect" redirect will work — a separate step from connect() since these aren't yet a full connection, just the app registration. */
    public function saveOauthConfig(Request $request, array $params): Response
    {
        $slug = $params['slug'];
        if (!in_array($slug, self::GOOGLE_OAUTH_PROVIDERS, true)) {
            return AjaxResponse::error('This integration does not use the OAuth client-id/secret flow.', 422);
        }

        $data = $this->validateOrFail($request, [
            'client_id' => 'required|string',
            'client_secret' => 'required|string',
        ]);

        $existing = (new IntegrationModel())->credentialsFor($slug) ?? [];
        (new IntegrationModel())->saveConfigOnly($slug, array_merge($existing, $data));

        return AjaxResponse::success(null, 'OAuth client configured. Click Connect to authorize.');
    }

    // ---- Google OAuth (Google OAuth + Google Calendar) ----

    public function googleAuthorize(Request $request, array $params): Response
    {
        $slug = $params['slug'];
        if (!in_array($slug, self::GOOGLE_OAUTH_PROVIDERS, true)) {
            return Response::html('Unknown provider.', 404);
        }

        $scope = $slug === 'google_calendar' ? GoogleOAuthService::SCOPE_CALENDAR : GoogleOAuthService::SCOPE_SIGNIN;
        $state = bin2hex(random_bytes(16));
        Session::set('_oauth_state_' . $slug, $state);

        $url = (new GoogleOAuthService())->buildAuthorizationUrl($slug, base_url("integrations/{$slug}/callback"), $scope, $state);

        if ($url === null) {
            return AjaxResponse::error('Google client ID is not configured for this integration yet. Enter it below first.', 422);
        }

        return Response::redirect($url);
    }

    public function googleCallback(Request $request, array $params): Response
    {
        $slug = $params['slug'];
        $expectedState = Session::get('_oauth_state_' . $slug);
        Session::remove('_oauth_state_' . $slug);

        if ($request->query('state') !== $expectedState) {
            return Response::html('Invalid OAuth state — please try connecting again.', 400);
        }

        $code = $request->query('code');
        if (!is_string($code)) {
            return Response::html('Google did not return an authorization code.', 400);
        }

        $result = (new GoogleOAuthService())->exchangeCodeForTokens($slug, $code, base_url("integrations/{$slug}/callback"));

        if (!$result['success']) {
            Session::flash('_integration_error', $result['error']);

            return Response::redirect(base_url('integrations'));
        }

        (new IntegrationModel())->connect($slug, [
            'access_token' => $result['access_token'],
            'refresh_token' => $result['refresh_token'],
            'expires_at' => $result['expires_at'],
        ], $this->currentUserId());

        ActivityLogger::logAction("Connected integration via OAuth: {$slug}", 'admin');

        return Response::redirect(base_url('integrations'));
    }

    // ---- Meta lead-ad webhooks (Facebook/Instagram) + generic social connect ----

    /** Meta's webhook verification handshake (GET with hub.challenge) — required before Meta will send real POST events. */
    public function metaWebhookVerify(Request $request): Response
    {
        $verifyToken = (new IntegrationModel())->credentialsFor('facebook')['webhook_verify_token'] ?? null;

        if ($verifyToken !== null && $request->query('hub_verify_token') === $verifyToken) {
            return Response::html((string) $request->query('hub_challenge'));
        }

        return Response::html('Forbidden', 403);
    }

    public function metaWebhookReceive(Request $request): Response
    {
        $payload = $request->all();
        $entries = $payload['entry'] ?? [];
        $processed = 0;

        foreach ($entries as $entry) {
            foreach ($entry['changes'] ?? [] as $change) {
                if (($change['field'] ?? '') !== 'leadgen') {
                    continue;
                }

                $leadgenId = (string) ($change['value']['leadgen_id'] ?? '');
                if ($leadgenId === '') {
                    continue;
                }

                $businessLineId = Session::get('_default_business_line_id') ?? 1;

                (new MetaIntegrationService())->processLeadAdWebhook('facebook', $leadgenId, (int) $businessLineId, function () {
                    return ['email' => null, 'phone' => null, 'full_name' => null];
                });
                $processed++;
            }
        }

        return AjaxResponse::success(['processed' => $processed]);
    }
}
