<?php
/**
 * Error Report Controller
 *
 * Handles frontend error reporting via email.
 * Sends error stack traces to support@fleekdash.com using \wp_mail().
 *
 * @package FleekDash V2.2
 * @since   V2.2 Refactoring
 */

namespace FleekDash\Controllers;

use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

// Load debug helpers
if (!function_exists('fleekdash_log_error')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

class ErrorReportController
{
    /**
     * Send error report via email
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response|WP_Error
     */
    public function sendReport(WP_REST_Request $request)
    {
        $response = new WP_Error(
            'error_report_exception',
            'Unknown error while sending report.',
            ['status' => 500]
        );

        try {
            $payload = $this->buildReportPayload($request);
            $subject = sprintf(
                '[FleekDash V2 Error] %s - %s',
                $payload['error_name'],
                (string) parse_url($payload['site_url'], PHP_URL_HOST)
            );
            $body = $this->buildEmailBody($payload);
            $headers = $this->buildEmailHeaders($payload['site_url'], $payload['current_user']->user_email ?? '');

            $sent = \wp_mail(
                'support@fleekdash.com',
                $subject,
                $body,
                $headers,
                []
            );

            if ($sent) {
                $response = new WP_REST_Response([
                    'success' => true,
                    'message' => 'Error report sent successfully to support@fleekdash.com'
                ], 200);
            } else {
                $response = $this->handleEmailFailure($subject, $body, $payload['site_url']);
            }
        } catch (\Exception $e) {
            $response = new WP_Error(
                'error_report_exception',
                'Exception while sending error report: ' . $e->getMessage(),
                ['status' => 500]
            );
        }

        return $response;
    }

    /**
     * Get license and plan information
     *
     * @return string Formatted license information
     */
    private function getLicenseInformation()
    {
        $license_key = \get_option('fleekdash_v2_license_key', 'No license key');
        $license_status = \get_option('fleekdash_v2_license_status', 'inactive');
        $instance_id = \get_option('fleekdash_v2_instance_id', 'No instance ID');
        $license_data = \get_option('fleekdash_v2_license_data', []);
        $tier_data = \get_option('fleekdash_v2_tier_data', []);

        [$license_type, $expiration] = $this->resolveLicenseTypeAndExpiration($license_data);
        [$plan_name, $plan_details] = $this->formatPlanDetails($tier_data);

        return sprintf(
            "License Key: %s\n" .
            "License Status: %s\n" .
            "License Type: %s\n" .
            "Expiration: %s\n" .
            "Instance ID: %s\n" .
            "Plan: %s%s",
            $license_key,
            strtoupper($license_status),
            $license_type,
            $expiration,
            $instance_id,
            $plan_name,
            $plan_details
        );
    }

    /**
     * Get active features information
     *
     * @return string Formatted features information
     */
    private function getFeaturesInformation()
    {
        $output = 'No specific features listed';

        try {
            $features_data = $this->getFeaturesResponseData();
            if (is_array($features_data)) {
                $output = $this->buildFeaturesOutput($features_data);
            } elseif (is_string($features_data)) {
                $output = $features_data;
            }
        } catch (\Exception $e) {
            $output = "Error retrieving features: " . $e->getMessage();
        }

        return $output;
    }

    /**
     * Get download links for the last N debug log files from uploads
     *
     * (v2.2) Returns array of download links for email reports
     * More efficient than attaching large files
     *
     * @param int $limit Number of files to return (default: 5)
     * @return array Array of file info with url, filename, size, modified timestamp
     */
    private function getDebugLogDownloadLinks($limit = 5)
    {
        $links = [];

        try {
            $upload_dir = \wp_upload_dir();
            if ($upload_dir['error']) {
                $upload_dir = ['basedir' => '', 'baseurl' => ''];
            }

            if (!empty($upload_dir['basedir'])) {
                $pattern = $upload_dir['basedir'] . '/debug-log-*.txt';
                $files = glob($pattern);

                if (!empty($files)) {
                    usort($files, function($a, $b) {
                        return filemtime($b) - filemtime($a);
                    });

                    $files = array_slice($files, 0, (int) $limit);

                    foreach ($files as $file) {
                        $filename = basename($file);
                        $url = $upload_dir['baseurl'] . '/' . $filename;

                        $links[] = [
                            'filename' => $filename,
                            'url' => $url,
                            'path' => $file,
                            'size' => filesize($file),
                            'modified' => filemtime($file),
                        ];
                    }
                }
            }
        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash Error Report: Error getting debug log links - ' . $e->getMessage());
        }

        return $links;
    }

    /**
     * Build sanitized error-report payload from request.
     *
     * @param WP_REST_Request $request
     * @return array<string, mixed>
     */
    private function buildReportPayload(WP_REST_Request $request): array
    {
        $current_user = \wp_get_current_user();
        $site_url = \get_site_url();

        return [
            'error_name' => \sanitize_text_field($request->get_param('error_name') ?? 'Unknown Error'),
            'error_message' => \sanitize_textarea_field($request->get_param('error_message') ?? 'No error message provided'),
            'error_stack' => \sanitize_textarea_field($request->get_param('error_stack') ?? 'No stack trace available'),
            'page_url' => \esc_url_raw($request->get_param('page_url') ?? 'Unknown URL'),
            'user_agent' => \sanitize_text_field($request->get_param('user_agent') ?? 'Unknown User Agent'),
            'additional_context' => \sanitize_textarea_field($request->get_param('additional_context') ?? ''),
            'current_user' => $current_user,
            'user_info' => $this->formatUserInfo($current_user),
            'site_url' => $site_url,
            'site_name' => \get_bloginfo('name'),
            'wp_version' => \get_bloginfo('version'),
            'plugin_version' => defined('FLEEKDASH_VERSION') ? FLEEKDASH_VERSION : 'Unknown',
            'license_info' => $this->getLicenseInformation(),
            'features_info' => $this->getFeaturesInformation(),
            'debug_links_text' => $this->buildDebugLogLinksText($this->getDebugLogDownloadLinks(5)),
        ];
    }

    /**
     * @param \WP_User $current_user
     * @return string
     */
    private function formatUserInfo(\WP_User $current_user): string
    {
        $user_info = 'User: Not authenticated';
        if ($current_user->exists()) {
            $user_info = sprintf(
                "User ID: %d\nUsername: %s\nEmail: %s\nRole: %s",
                $current_user->ID,
                $current_user->user_login,
                $current_user->user_email,
                implode(', ', $current_user->roles)
            );
        }

        return $user_info;
    }

    /**
     * @param array<int, array<string, mixed>> $debug_log_links
     * @return string
     */
    private function buildDebugLogLinksText(array $debug_log_links): string
    {
        $text = "\nDEBUG LOG FILES:\n---------------\nNo debug log files found in uploads folder.\nUse the 'Download' button in Debug Settings to save debug.log to uploads.\n";

        if (!empty($debug_log_links)) {
            $text = "\nDEBUG LOG FILES (Available for Download):\n----------------------------------------\n";
            foreach ($debug_log_links as $index => $log_info) {
                $file_size_kb = round(((float) ($log_info['size'] ?? 0)) / 1024, 2);
                $modified_date = date('Y-m-d H:i:s', (int) ($log_info['modified'] ?? 0));
                $text .= sprintf(
                    "%d. %s\n   URL: %s\n   Size: %s KB | Modified: %s\n\n",
                    $index + 1,
                    (string) ($log_info['filename'] ?? 'unknown-file'),
                    (string) ($log_info['url'] ?? ''),
                    $file_size_kb,
                    $modified_date
                );
            }
            $text .= "Total files: " . count($debug_log_links) . "\n";
            $text .= "Note: These files are saved in wp-content/uploads/ with timestamps.\n";
        }

        return $text;
    }

    /**
     * @param array<string, mixed> $payload
     * @return string
     */
    private function buildEmailBody(array $payload): string
    {
        $additional_context_text = '';
        if (!empty($payload['additional_context'])) {
            $additional_context_text = "\nADDITIONAL CONTEXT:\n------------------\n" . $payload['additional_context'];
        }

        return sprintf(
            "FleekDash V2 Error Report\n" .
            "========================\n\n" .
            "ERROR DETAILS:\n" .
            "-------------\n" .
            "Error Type: %s\n" .
            "Error Message: %s\n" .
            "Page URL: %s\n" .
            "Timestamp: %s\n\n" .
            "STACK TRACE:\n" .
            "------------\n" .
            "%s\n\n" .
            "USER INFORMATION:\n" .
            "----------------\n" .
            "%s\n\n" .
            "SITE INFORMATION:\n" .
            "----------------\n" .
            "Site Name: %s\n" .
            "Site URL: %s\n" .
            "WordPress Version: %s\n" .
            "FleekDash Version: %s\n\n" .
            "LICENSE & PLAN INFORMATION:\n" .
            "--------------------------\n" .
            "%s\n" .
            "ACTIVE FEATURES:\n" .
            "---------------\n" .
            "%s\n" .
            "BROWSER INFORMATION:\n" .
            "------------------\n" .
            "User Agent: %s\n" .
            "%s" .
            "%s",
            (string) $payload['error_name'],
            (string) $payload['error_message'],
            (string) $payload['page_url'],
            \current_time('mysql'),
            (string) $payload['error_stack'],
            (string) $payload['user_info'],
            (string) $payload['site_name'],
            (string) $payload['site_url'],
            (string) $payload['wp_version'],
            (string) $payload['plugin_version'],
            (string) $payload['license_info'],
            (string) $payload['features_info'],
            (string) $payload['user_agent'],
            $additional_context_text,
            (string) $payload['debug_links_text']
        );
    }

    /**
     * @param string $site_url
     * @param string $user_email
     * @return array<int, string>
     */
    private function buildEmailHeaders(string $site_url, string $user_email): array
    {
        $headers = [
            'Content-Type: text/plain; charset=UTF-8',
            'From: ' . \get_bloginfo('name') . ' <noreply@' . parse_url($site_url, PHP_URL_HOST) . '>'
        ];

        if (!empty($user_email)) {
            $headers[] = 'Reply-To: ' . $user_email;
        }

        return $headers;
    }

    /**
     * @param string $subject
     * @param string $body
     * @param string $site_url
     * @return WP_REST_Response|WP_Error
     */
    private function handleEmailFailure(string $subject, string $body, string $site_url)
    {
        fleekdash_log_error('FleekDash Error Report (Email failed to send):');
        fleekdash_log_error($subject);
        fleekdash_log_error($body);

        $is_local = (
            strpos($site_url, 'localhost') !== false ||
            strpos($site_url, '.test') !== false ||
            strpos($site_url, '.local') !== false ||
            strpos($site_url, '127.0.0.1') !== false
        );

        if ($is_local) {
            return new WP_REST_Response([
                'success' => true,
                'message' => 'Error report logged (local environment - email not sent)',
                'dev_mode' => true
            ], 200);
        }

        return new WP_Error(
            'email_send_failed',
            'Email not sent. Please set up your email service.',
            [
                'status' => 500,
                'user_friendly' => true,
                'code' => 'email_send_failed'
            ]
        );
    }

    /**
     * @param array<string, mixed> $license_data
     * @return array{0:string,1:string}
     */
    private function resolveLicenseTypeAndExpiration(array $license_data): array
    {
        $license_type = 'Unknown';
        $expiration = 'Unknown';

        if (!empty($license_data)) {
            if (isset($license_data['ltdeal']) && $license_data['ltdeal']) {
                $license_type = 'Lifetime Deal (LTD)';
                $expiration = 'Never (Lifetime)';
            } elseif (isset($license_data['expiration_date'])) {
                $license_type = 'Subscription';
                $expiration = (string) $license_data['expiration_date'];
            } elseif (isset($license_data['created_at'])) {
                $license_type = 'Regular License';
                $expiration = 'Based on subscription';
            }
        }

        return [$license_type, $expiration];
    }

    /**
     * @param array<string, mixed> $tier_data
     * @return array{0:string,1:string}
     */
    private function formatPlanDetails(array $tier_data): array
    {
        $plan_name = 'Unknown Plan';
        $plan_details = '';

        if (!empty($tier_data)) {
            $plan_name = (string) ($tier_data['tier_name'] ?? $tier_data['name'] ?? 'Unknown Plan');
            if (isset($tier_data['max_quantity'])) {
                $plan_details .= "\n  Max Activations: " . $tier_data['max_quantity'];
            }
            if (isset($tier_data['tier_price'])) {
                $plan_details .= "\n  Price: $" . $tier_data['tier_price'];
            }
            if (isset($tier_data['id'])) {
                $plan_details .= "\n  Tier ID: " . $tier_data['id'];
            }
        }

        return [$plan_name, $plan_details];
    }

    /**
     * @return array<string, mixed>|string
     */
    private function getFeaturesResponseData()
    {
        if (!class_exists('\FleekDash\API\FeatureController')) {
            return 'Feature controller not available';
        }

        $controller = \FleekDash\API\FeatureController::getInstance();
        $request = new \WP_REST_Request('GET', '/fleekdash/v1/features/user');
        $request->set_param('app_name', 'fleekdash');
        $response = $controller->getUserFeatures($request);

        if (is_wp_error($response)) {
            return 'Error loading features: ' . $response->get_error_message();
        }

        $data = $response->get_data();
        return is_array($data) ? $data : 'No feature data available';
    }

    /**
     * @param array<string, mixed> $features_data
     * @return string
     */
    private function buildFeaturesOutput(array $features_data): string
    {
        $features_list = $this->formatFeaturesList($features_data['features'] ?? []);
        $limits_list = $this->formatFeatureLimits($features_data['limits'] ?? []);

        $output = !empty($features_list)
            ? "Enabled Features:\n" . implode("\n", $features_list)
            : 'No specific features listed';

        if (!empty($limits_list)) {
            $output .= "\n\nLimits:\n" . implode("\n", $limits_list);
        }

        $output = $this->appendFeaturesMetadata($output, $features_data);
        return $output;
    }

    /**
     * @param mixed $features
     * @return array<int, string>
     */
    private function formatFeaturesList($features): array
    {
        $features_list = [];
        if (!is_array($features)) {
            return $features_list;
        }

        foreach ($features as $feature) {
            if (is_array($feature)) {
                $features_list[] = $this->formatSingleFeatureEntry($feature);
                continue;
            }

            $features_list[] = "  - {$feature}: YES";
        }

        return $features_list;
    }

    /**
     * @param array<string, mixed> $feature
     * @return string
     */
    private function formatSingleFeatureEntry(array $feature): string
    {
        $feature_name = $feature['feature_name'] ?? $feature['name'] ?? 'Unknown';
        $enabled = $this->resolveEnabledLabel($feature);
        return "  - {$feature_name}: {$enabled}";
    }

    /**
     * @param array<string, mixed> $feature
     * @return string
     */
    private function resolveEnabledLabel(array $feature): string
    {
        $enabled = 'YES';
        if (isset($feature['enabled']) && $feature['enabled'] === false) {
            $enabled = 'NO';
        }
        return $enabled;
    }

    /**
     * @param mixed $limits
     * @return array<int, string>
     */
    private function formatFeatureLimits($limits): array
    {
        $limits_list = [];

        if (is_array($limits)) {
            foreach ($limits as $limit_name => $limit_value) {
                if (is_array($limit_value)) {
                    $display_value = $limit_value['display_value'] ?? $limit_value['limit_value'] ?? json_encode($limit_value);
                    if (isset($limit_value['feature_name'])) {
                        $feature_name = $limit_value['feature_name'];
                        $limit_description = $limit_value['description'] ?? $display_value;
                        $limits_list[] = "  - {$feature_name}: {$limit_description}";
                    } else {
                        $limits_list[] = "  - {$limit_name}: {$display_value}";
                    }
                } else {
                    $limits_list[] = "  - {$limit_name}: {$limit_value}";
                }
            }
        }

        return $limits_list;
    }

    /**
     * @param string $output
     * @param array<string, mixed> $features_data
     * @return string
     */
    private function appendFeaturesMetadata(string $output, array $features_data): string
    {
        if (isset($features_data['tier_id'])) {
            $output .= "\n\nTier ID: " . $features_data['tier_id'];
        }
        if (isset($features_data['admin_override']) && $features_data['admin_override']) {
            $output .= "\nAdmin Override: YES (all features enabled)";
        }
        return $output;
    }
}
