<?php

namespace EasyLinkAutomations\HTTP\Controllers;

if (!defined('ABSPATH')) {
    exit;
}

use EasyLinkAutomations\Auth\AuthType;
use EasyLinkAutomations\Auth\CredentialTester;
use EasyLinkAutomations\Auth\EncryptionService;
use EasyLinkAutomations\Auth\OAuth2Handler;
use EasyLinkAutomations\Auth\PlatformAuthRegistry;
use EasyLinkAutomations\HTTP\Request\Request;
use EasyLinkAutomations\HTTP\Response;
use EasyLinkAutomations\Models\Connection;

/**
 * Manages third-party app connections and credentials.
 *
 * Supports multiple auth types: API Key, Bearer Token, Basic Auth, OAuth2.
 * Credentials are encrypted before storage using EncryptionService.
 */
final class ConnectionController
{
    /**
     * List connections (paginated).
     */
    public function index(Request $request): Response
    {
        $page     = (int) ($request->get('page') ?? 1);
        $perPage  = (int) ($request->get('per_page') ?? 20);
        $platform = $request->get('platform');

        $result = Connection::paginate($page, $perPage, $platform);

        // Strip credentials from response
        $items = array_map(function (array $conn) {
            unset($conn['credentials'], $conn['token_data']);
            $conn['has_credentials'] = true;

            return $conn;
        }, $result['items']);

        return Response::success([
            'connections' => $items,
            'total'       => $result['total'],
            'page'        => $page,
            'per_page'    => $perPage,
        ]);
    }

    /**
     * Show a single connection (credentials redacted).
     */
    public function show(Request $request, int $connectionId): Response
    {
        $connection = Connection::find($connectionId);

        if (!$connection) {
            return Response::error(__('Connection not found', 'easylink-automations'))->httpStatus(404);
        }

        // Redact credentials but indicate they exist
        unset($connection['credentials'], $connection['token_data']);
        $connection['has_credentials'] = true;

        // Include platform schema if available
        $platformClass = PlatformAuthRegistry::get($connection['platform'] ?? '');
        if ($platformClass) {
            $connection['platform_schema'] = $platformClass::toArray();
        }

        return Response::success(['connection' => $connection]);
    }

    /**
     * Create a new connection.
     */
    public function store(Request $request): Response
    {

        $name        = sanitize_text_field($request->get('name') ?? '');
        $platform    = sanitize_text_field($request->get('platform') ?? '');
        $authType    = sanitize_text_field($request->get('auth_type') ?? AuthType::API_KEY);
        $credentials = $request->get('credentials') ?? [];
        $status      = sanitize_text_field($request->get('status') ?? 'active');
        
        if (empty($name)) {
            return Response::error(__('Name is required', 'easylink-automations'))->httpStatus(400);
        }

        if (empty($platform)) {
            return Response::error(__('Platform is required', 'easylink-automations'))->httpStatus(400);
        }

        if (!AuthType::isValid($authType)) {
            return Response::error('Invalid auth type: ' . $authType)->httpStatus(400);
        }

        // Parse credentials
        if (is_string($credentials)) {
            $credentials = json_decode($credentials, true) ?? [];
        }

        // For OAuth2, save with pending status — tokens come after the OAuth dance
        if ($authType === AuthType::OAUTH2) {
            $status = 'pending';
        }

        // Encrypt credentials before storing
        $encryptedCredentials = EncryptionService::encrypt($credentials);

        $connectionId = Connection::create([
            'name'        => $name,
            'platform'    => $platform,
            'auth_type'   => $authType,
            'credentials' => $encryptedCredentials,
            'status'      => $status,
            'created_by'  => get_current_user_id(),
        ]);

        if (!$connectionId) {
            return Response::error(__('Failed to create connection', 'easylink-automations'))->httpStatus(500);
        }

        return Response::success([
            'message'       => __('Connection created successfully', 'easylink-automations'),
            'connection_id' => $connectionId,
        ]);
    }

    /**
     * Update a connection.
     */
    public function update(Request $request): Response
    {
        $connectionId = (int) ($request->get('connection_id') ?? 0);

        if (!$connectionId) {
            return Response::error(__('Connection ID is required', 'easylink-automations'))->httpStatus(400);
        }

        $connection = Connection::find($connectionId);

        if (!$connection) {
            return Response::error(__('Connection not found', 'easylink-automations'))->httpStatus(404);
        }

        $name        = sanitize_text_field($request->get('name') ?? $connection['name']);
        $status      = sanitize_text_field($request->get('status') ?? $connection['status']);
        $credentials = $request->get('credentials');

        $updateData = [
            'name'   => $name,
            'status' => $status,
        ];

        // Only update credentials if provided
        if ($credentials !== null) {
            if (is_string($credentials)) {
                $credentials = json_decode($credentials, true) ?? [];
            }
            $updateData['credentials'] = EncryptionService::encrypt($credentials);
        }

        $updated = Connection::update($connectionId, $updateData);

        if (!$updated) {
            return Response::error(__('Failed to update connection', 'easylink-automations'))->httpStatus(500);
        }

        return Response::success([
            'message' => __('Connection updated successfully', 'easylink-automations'),
        ]);
    }

    /**
     * Delete a connection.
     */
    public function destroy(Request $request): Response
    {
        $connectionId = (int) ($request->get('connection_id') ?? 0);

        if (!$connectionId) {
            return Response::error(__('Connection ID is required', 'easylink-automations'))->httpStatus(400);
        }

        $connection = Connection::find($connectionId);

        if (!$connection) {
            return Response::error(__('Connection not found', 'easylink-automations'))->httpStatus(404);
        }

        $deleted = Connection::delete($connectionId);

        if (!$deleted) {
            return Response::error(__('Failed to delete connection', 'easylink-automations'))->httpStatus(500);
        }

        return Response::success([
            'message' => __('Connection deleted successfully', 'easylink-automations'),
        ]);
    }

    // ─── New endpoints ───────────────────────────────────────────

    /**
     * List available platforms and their auth schemas.
     *
     * Includes the OAuth2 redirect URL so users can register it with
     * providers when creating their OAuth app credentials.
     */
    public function platforms(Request $request): Response
    {
        return Response::success([
            'platforms'         => PlatformAuthRegistry::toArray(),
            'oauth2_redirect_url' => OAuth2Handler::getCallbackUrl(),
        ]);
    }

    /**
     * Test a connection's credentials.
     */
    public function test(Request $request): Response
    {
        $connectionId = (int) ($request->get('connection_id') ?? 0);

        if ($connectionId > 0) {
            // Test existing connection
            $result = CredentialTester::testConnection($connectionId);
        } else {
            // Test raw credentials (before saving)
            $platform    = sanitize_text_field($request->get('platform') ?? '');
            $credentials = $request->get('credentials') ?? [];

            if (is_string($credentials)) {
                $credentials = json_decode($credentials, true) ?? [];
            }

            if (empty($platform)) {
                return Response::error(__('Platform is required', 'easylink-automations'))->httpStatus(400);
            }

            $result = CredentialTester::testRaw($platform, $credentials);
        }

        if ($result['success']) {
            return Response::success($result);
        }

        return Response::error($result['message']);
    }

    /**
     * Initiate OAuth2 authorization flow.
     *
     * Returns the authorization URL that the frontend should open in a popup.
     */
    public function oauthStart(Request $request): Response
    {
        $connectionId = (int) ($request->get('connection_id') ?? 0);

        if (!$connectionId) {
            return Response::error(__('Connection ID is required', 'easylink-automations'))->httpStatus(400);
        }

        $connection = Connection::find($connectionId);

        if (!$connection) {
            return Response::error(__('Connection not found', 'easylink-automations'))->httpStatus(404);
        }

        if (($connection['auth_type'] ?? '') !== AuthType::OAUTH2) {
            return Response::error(__('Connection is not OAuth2 type', 'easylink-automations'))->httpStatus(400);
        }

        $authUrl = OAuth2Handler::getAuthorizationUrl(
            $connection['platform'],
            $connectionId
        );

        if (!$authUrl) {
            return Response::error(__('Failed to generate authorization URL', 'easylink-automations'))->httpStatus(500);
        }

        return Response::success([
            'auth_url' => $authUrl,
        ]);
    }

    /**
     * Handle OAuth2 callback from external providers.
     *
     * This is called by the OAuth provider after user authorization.
     * Returns HTML that communicates the result to the opener window.
     */
    public function oauthCallback(Request $request): void
    {
        $code  = sanitize_text_field($request->get('code') ?? '');
        $state = sanitize_text_field($request->get('state') ?? '');

        if (empty($code) || empty($state)) {
            wp_die('Missing authorization code or state parameter.', 'OAuth Error', ['response' => 400]);
        }

        $result = OAuth2Handler::handleCallback($code, $state, $request->all());

        // Return an HTML page that communicates the result to the opener window and closes the popup
        $status  = $result['success'] ? 'success' : 'error';
        $message = esc_js($result['message']);
        $bodyMsg = esc_html($result['message']);

        header('Content-Type: text/html; charset=utf-8');
        echo '<!DOCTYPE html><html><head><title>EasyLink Automations — OAuth</title></head><body>';
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $bodyMsg is esc_html() above.
        echo '<p>' . $bodyMsg . '</p>';
        echo '<script>';
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $message and status are esc_js() above.
        echo "if (window.opener) { window.opener.postMessage({ type: 'easylink_automations_oauth_callback', status: '" . esc_js($status) . "', message: '" . $message . "' }, window.location.origin); window.close(); }";
        echo '</script></body></html>';
        exit;
    }
}
