<?php

namespace Formatrica\REST;

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

use Formatrica\Support\Secrets;
use Formatrica\Email\Email_Service;
use Formatrica\Documents\Pdf_Branding;

final class Settings_Controller extends Base_Rest_Controller
{
    public function register_routes(): void
    {
        // PDF branding lives in app/Documents (Pro documents.pdf) — stripped
        // from the wporg package, so the route only registers when it ships.
        if (class_exists(Pdf_Branding::class)) {
            register_rest_route(
                self::NAMESPACE,
                '/settings/pdf',
                [
                    [
                        'methods' => \WP_REST_Server::READABLE,
                        'permission_callback' => [$this, 'permissions_check'],
                        'callback' => [$this, 'get_pdf_settings'],
                    ],
                    [
                        'methods' => \WP_REST_Server::CREATABLE,
                        'permission_callback' => [$this, 'permissions_check'],
                        'callback' => [$this, 'save_pdf_settings'],
                    ],
                ]
            );
        }

        register_rest_route(
            self::NAMESPACE,
            '/settings/email',
            [
                [
                    'methods' => \WP_REST_Server::READABLE,
                    'permission_callback' => [$this, 'permissions_check'],
                    'callback' => [$this, 'get_email_settings'],
                ],
                [
                    'methods' => \WP_REST_Server::CREATABLE,
                    'permission_callback' => [$this, 'permissions_check'],
                    'callback' => [$this, 'save_email_settings'],
                    'args' => [
                        'from_name' => ['required' => false],
                        'from_email' => ['required' => false],
                        'recipient' => ['required' => false],
                        'delivery' => ['required' => true],
                    ],
                ],
            ]
        );

        register_rest_route(
            self::NAMESPACE,
            '/settings/email/test',
            [
                [
                    'methods' => \WP_REST_Server::CREATABLE,
                    'permission_callback' => [$this, 'permissions_check'],
                    'callback' => [$this, 'send_test_email'],
                    'args' => [
                        'recipient' => ['required' => true],
                    ],
                ],
            ]
        );

        register_rest_route(
            self::NAMESPACE,
            '/settings/email/diagnostics',
            [
                [
                    'methods' => \WP_REST_Server::READABLE,
                    'permission_callback' => [$this, 'permissions_check'],
                    'callback' => [$this, 'get_email_diagnostics'],
                ],
            ]
        );
    }

    public function get_pdf_settings(\WP_REST_Request $request): \WP_REST_Response
    {
        return new \WP_REST_Response(['success' => true, 'settings' => Pdf_Branding::for_client()], 200);
    }

    public function save_pdf_settings(\WP_REST_Request $request): \WP_REST_Response
    {
        $body = $request->get_json_params();
        $body = is_array($body) ? $body : [];

        return new \WP_REST_Response(['success' => true, 'settings' => Pdf_Branding::save($body)], 200);
    }

    public function get_email_settings(\WP_REST_Request $request): \WP_REST_Response
    {
        $nonce_check = $this->verify_rest_nonce_or_error($request);
        if ($nonce_check instanceof \WP_Error) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => $nonce_check->get_error_message(),
            ], (int) ($nonce_check->get_error_data('status') ?: 403));
        }

        $settings = get_option('formatrica_settings', []);
        $email = is_array($settings['email'] ?? null) ? $settings['email'] : [];
        $delivery = is_array($email['delivery'] ?? null) ? $email['delivery'] : $this->default_delivery();

        // Redact secrets
        $sanitized = [
            'from_name' => isset($email['from_name']) ? (string) $email['from_name'] : get_bloginfo('name'),
            'from_email' => isset($email['from_email']) ? (string) $email['from_email'] : $this->default_from_email(),
            'recipient' => isset($email['recipient']) && is_email($email['recipient'])
                ? (string) $email['recipient']
                : (string) get_option('admin_email'),
            'delivery' => $this->redact_delivery($delivery),
        ];

        return new \WP_REST_Response([
            'success' => true,
            'settings' => $sanitized,
        ]);
    }

    public function get_email_diagnostics(\WP_REST_Request $request): \WP_REST_Response
    {
        $nonce_check = $this->verify_rest_nonce_or_error($request);
        if ($nonce_check instanceof \WP_Error) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => $nonce_check->get_error_message(),
            ], (int) ($nonce_check->get_error_data('status') ?: 403));
        }

        $warning_at = get_transient('formatrica_email_warning');
        $wp_mail_error = get_transient('formatrica_wp_mail_error_details');
        $wp_mail_success = get_transient('formatrica_wp_mail_last_success');

        $diagnostics = [
            'warningAt' => is_int($warning_at) ? $warning_at : null,
            'wpMail' => [
                'lastError' => is_array($wp_mail_error) ? $wp_mail_error : null,
                'lastSuccess' => is_array($wp_mail_success) ? $wp_mail_success : null,
            ],
        ];

        return new \WP_REST_Response([
            'success' => true,
            'diagnostics' => $diagnostics,
        ]);
    }

    public function save_email_settings(\WP_REST_Request $request): \WP_REST_Response
    {
        $nonce_check = $this->verify_rest_nonce_or_error($request);
        if ($nonce_check instanceof \WP_Error) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => $nonce_check->get_error_message(),
            ], (int) ($nonce_check->get_error_data('status') ?: 403));
        }

        $params = $request->get_json_params();

    $from_name = isset($params['from_name']) ? sanitize_text_field((string) $params['from_name']) : get_bloginfo('name');
    $from_email = isset($params['from_email']) ? sanitize_email((string) $params['from_email']) : $this->default_from_email();
    $recipient = isset($params['recipient']) ? sanitize_email((string) $params['recipient']) : '';
        $delivery = is_array($params['delivery'] ?? null) ? $params['delivery'] : [];
        $delivery = $this->sanitize_delivery($delivery, $this->get_existing_delivery());

        $settings = get_option('formatrica_settings', []);
        if (!is_array($settings)) {
            $settings = [];
        }

        $settings['email'] = [
            'from_name' => $from_name,
            'from_email' => $from_email,
            'recipient' => $recipient,
            'delivery' => $delivery,
        ];

        update_option('formatrica_settings', $settings, false);

        return new \WP_REST_Response([
            'success' => true,
            'saved' => true,
        ]);
    }

    public function send_test_email(\WP_REST_Request $request): \WP_REST_Response
    {
        $nonce_check = $this->verify_rest_nonce_or_error($request);
        if ($nonce_check instanceof \WP_Error) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => $nonce_check->get_error_message(),
            ], (int) ($nonce_check->get_error_data('status') ?: 403));
        }

        $recipient = isset($request['recipient']) ? sanitize_email((string) $request['recipient']) : '';

        if ($recipient === '' || !is_email($recipient)) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => __('Invalid recipient email.', 'formatrica'),
            ], 400);
        }

        $settings = get_option('formatrica_settings', []);
        $email = is_array($settings['email'] ?? null) ? $settings['email'] : [];
        $delivery = is_array($email['delivery'] ?? null) ? $email['delivery'] : $this->default_delivery();

        $service = new Email_Service();

        $result = $service->send_generic([
            'email_delivery' => $delivery,
        ], [
            'to' => $recipient,
            'subject' => __('Test email from Formatrica (Global settings)', 'formatrica'),
            'html' => '<p>' . esc_html__('Success! Global email settings appear to work.', 'formatrica') . '</p>',
            'from_name' => isset($email['from_name']) ? (string) $email['from_name'] : get_bloginfo('name'),
            'from_email' => isset($email['from_email']) ? (string) $email['from_email'] : $this->default_from_email(),
        ]);

        if ($result['sent']) {
            return new \WP_REST_Response([
                'success' => true,
                'message' => __('Test email sent. Check your inbox.', 'formatrica'),
            ]);
        }

        return new \WP_REST_Response([
            'success' => false,
            'message' => $result['error'] ?? __('Failed to send test email.', 'formatrica'),
        ], 500);
    }

    private function default_delivery(): array
    {
        return [
            'provider' => 'wordpress',
            'sendgrid' => ['api_key' => ''],
            'mailgun' => ['api_key' => '', 'domain' => '', 'region' => 'us'],
            'postmark' => ['api_token' => ''],
            'brevo' => ['api_key' => ''],
            'amazon_ses' => ['access_key' => '', 'secret_key' => '', 'region' => 'us-east-1'],
            'mailpit' => ['host' => '127.0.0.1', 'port' => 1025],
            'smtp2go' => ['api_key' => ''],
            'smtp' => ['host' => '', 'port' => 587, 'encryption' => 'tls', 'username' => '', 'password' => ''],
        ];
    }

    private function get_existing_delivery(): array
    {
        $settings = get_option('formatrica_settings', []);
        $email = is_array($settings['email'] ?? null) ? $settings['email'] : [];
        return is_array($email['delivery'] ?? null) ? $email['delivery'] : [];
    }

    private function redact_delivery(array $delivery): array
    {
        $out = $this->default_delivery();
        $out = wp_parse_args($delivery, $out);

        // Redact and expose password_set flags where applicable
        if (!empty($out['smtp']['password'])) {
            $out['smtp']['password'] = '';
            $out['smtp']['password_set'] = true;
        } else {
            $out['smtp']['password_set'] = false;
        }

        // Provider API keys are write-only (Phase 6): the browser gets only
        // the *_set flag, never the stored (encrypted or legacy) value.
        foreach ([
            ['sendgrid', 'api_key'],
            ['mailgun', 'api_key'],
            ['postmark', 'api_token'],
            ['brevo', 'api_key'],
            ['amazon_ses', 'secret_key'],
            ['smtp2go', 'api_key'],
        ] as [$prov, $key]) {
            $out[$prov][$key . '_set'] = !empty($out[$prov][$key]);
            $out[$prov][$key] = '';
        }

        return $out;
    }

    private function sanitize_delivery(array $incoming, array $existing): array
    {
        $defaults = $this->default_delivery();
        $merged = wp_parse_args($incoming, $defaults);

        $allowed = ['wordpress', 'sendgrid', 'mailgun', 'postmark', 'brevo', 'amazon_ses', 'mailpit', 'smtp2go', 'smtp'];
        $provider = isset($merged['provider']) ? sanitize_key((string) $merged['provider']) : 'wordpress';
        $merged['provider'] = in_array($provider, $allowed, true) ? $provider : 'wordpress';

        // Provider API keys are write-only secrets (Phase 6): an empty incoming
        // value keeps the stored one — the browser only ever gets the *_set flag
        // (redact_delivery) — and a new value is encrypted at rest. Pre-Phase-6
        // plaintext values keep working via Secrets::reveal() at send time.
        $delivery_secret_keys = [
            ['sendgrid', 'api_key'],
            ['mailgun', 'api_key'],
            ['postmark', 'api_token'],
            ['brevo', 'api_key'],
            ['amazon_ses', 'secret_key'],
            ['smtp2go', 'api_key'],
        ];
        foreach ($delivery_secret_keys as [$prov, $key]) {
            $merged[$prov][$key] = Secrets::store_write_only(
                sanitize_text_field((string) ($merged[$prov][$key] ?? '')),
                (string) ($existing[$prov][$key] ?? '')
            );
            unset($merged[$prov][$key . '_set']);
        }

        $merged['mailgun']['domain'] = isset($merged['mailgun']['domain']) ? sanitize_text_field((string) $merged['mailgun']['domain']) : '';
        $region = isset($merged['mailgun']['region']) ? (string) $merged['mailgun']['region'] : 'us';
        $merged['mailgun']['region'] = in_array($region, ['us', 'eu'], true) ? $region : 'us';

        $merged['amazon_ses']['access_key'] = isset($merged['amazon_ses']['access_key']) ? sanitize_text_field((string) $merged['amazon_ses']['access_key']) : '';
        $merged['amazon_ses']['region'] = isset($merged['amazon_ses']['region']) ? sanitize_text_field((string) $merged['amazon_ses']['region']) : 'us-east-1';

        $merged['mailpit']['host'] = isset($merged['mailpit']['host']) ? sanitize_text_field((string) $merged['mailpit']['host']) : '127.0.0.1';
        $merged['mailpit']['port'] = isset($merged['mailpit']['port']) ? max(1, (int) $merged['mailpit']['port']) : 1025;

        $merged['smtp']['host'] = isset($merged['smtp']['host']) ? sanitize_text_field((string) $merged['smtp']['host']) : '';
        $merged['smtp']['port'] = isset($merged['smtp']['port']) ? max(1, (int) $merged['smtp']['port']) : 587;
        $smtp_enc = isset($merged['smtp']['encryption']) ? (string) $merged['smtp']['encryption'] : 'tls';
        $merged['smtp']['encryption'] = in_array($smtp_enc, ['none', 'ssl', 'tls'], true) ? $smtp_enc : 'tls';
        $merged['smtp']['username'] = isset($merged['smtp']['username']) ? sanitize_text_field((string) $merged['smtp']['username']) : '';

        $existing_password = isset($existing['smtp']['password']) ? (string) $existing['smtp']['password'] : '';
        $incoming_password = isset($incoming['smtp']['password']) ? trim((string) $incoming['smtp']['password']) : '';
        $password_set_flag = !empty($incoming['smtp']['password_set']);

        if ($incoming_password === '' && $password_set_flag && $existing_password !== '') {
            $merged['smtp']['password'] = $existing_password;
        } elseif ($incoming_password !== '') {
            $merged['smtp']['password'] = Secrets::encrypt($incoming_password);
        } else {
            $merged['smtp']['password'] = '';
        }

        unset($merged['smtp']['password_set']);

        return $merged;
    }

    private function default_from_email(): string
    {
        $domain = wp_parse_url(home_url(), PHP_URL_HOST);

        if (!is_string($domain) || empty($domain)) {
            $domain = 'example.com';
        }

        return 'noreply@' . preg_replace('/^www\./', '', $domain);
    }
}
