<?php
// components/Data/Health.php
namespace Components\Data;

use Components\Base;

class Health extends Base
{
    /**
     * Get open health issues.
     */
    public static function getIssues(): array
    {
        $issues = [];

        if (function_exists('mh_get_application_health_issues')) {
            $candidate = call_user_func('mh_get_application_health_issues');
            if (is_array($candidate)) {
                $issues = $candidate;
            }
        } elseif (function_exists('mh_get_health_issues')) {
            $candidate = call_user_func('mh_get_health_issues');
            if (is_array($candidate)) {
                $issues = $candidate;
            }
        }

        return self::normalizeIssues($issues);
    }

    /**
     * Get normalized system checks (legacy wrappers + local checks).
     */
    public static function getChecks($refresh = false): array
    {
        $legacy = self::getLegacySystemStatusData($refresh);
        if (empty($legacy)) {
            return [];
        }

        $checks = [];
        $checks[] = self::buildSummaryCheck($legacy);
        $checks[] = self::buildLastActionCheck($legacy);

        $subscriptionCheck = self::buildSubscriptionCheck($legacy);
        if (!empty($subscriptionCheck)) {
            $checks[] = $subscriptionCheck;
        }

        $emailCheck = self::buildEmailCheck($legacy);
        if (!empty($emailCheck)) {
            $checks[] = $emailCheck;
        }

        return array_values(array_filter($checks, static function ($check) {
            return is_array($check) && trim((string)($check['title'] ?? '')) !== '';
        }));
    }

    /**
     * Get summary for polling endpoint.
     */
    public static function getPollSummary(): array
    {
        $issues = self::getIssues();
        $checks = array_values(array_filter(self::getChecks(), static function (array $check): bool {
            return ($check['key'] ?? '') !== 'overall';
        }));

        $criticalCount = 0;
        $warningCount = 0;

        $checkOkCount = 0;
        $checkNotOkCount = 0;

        foreach ($issues as $issue) {
            if (($issue['severity'] ?? 'warning') === 'critical') {
                $criticalCount++;
            } else {
                $warningCount++;
            }
        }

        foreach ($checks as $check) {
            if (($check['state'] ?? 'not_ok') === 'ok') {
                $checkOkCount++;
                continue;
            }

            $checkNotOkCount++;
            if (($check['severity'] ?? 'warning') === 'critical') {
                $criticalCount++;
            } else {
                $warningCount++;
            }
        }

        return [
            'count' => $criticalCount + $warningCount,
            'critical_count' => $criticalCount,
            'warning_count' => $warningCount,
            'issue_count' => count($issues),
            'check_count' => count($checks),
            'check_ok_count' => $checkOkCount,
            'check_not_ok_count' => $checkNotOkCount,
        ];
    }

    private static function getLegacySystemStatusData($refresh = false): array
    {
        if (!class_exists('mailbeez_system') || !method_exists('mailbeez_system', 'getSystemStatusData')) {
            return [];
        }

        if (!class_exists('mailbeez_cache')) {
            return [];
        }

        // SMTP connection test (triggered via getSystemStatusData) is slow, cache results
        $cache = new \mailbeez_cache();
        $cache->app_cache_time = 600; // Increased to 10 minutes as requested
        $cache->set_cache_id('health_status', 'health');

        if ($refresh) {
            $cache->purge_cache('app');
        }

        $cached = $cache->read_cache('app');
        if (is_array($cached) && isset($cached['value'])) {
            return $cached['value'];
        }

        try {
            $data = \mailbeez_system::getSystemStatusData($refresh);
            if (is_array($data)) {
                $cache->set_cache($data, 'app');
            }
        } catch (\Throwable $e) {
            return [];
        }

        return is_array($data) ? $data : [];
    }

    private static function buildSummaryCheck(array $legacy): array
    {
        $statusRaw = (string)($legacy['status_summary'] ?? '');
        $statusCode = strtoupper(trim($statusRaw));
        $status = self::normalizeStatus($statusCode);
        $statusLabel = self::legacyStatusLabel($statusCode);

        return self::buildCheck(
            'overall',
            self::lng('UI_APPLICATION_HEALTH_CHECK_SUMMARY_TITLE', 'System Status'),
            $status,
            $status['state'] === 'ok'
                ? self::lng('UI_APPLICATION_HEALTH_CHECK_SUMMARY_OK', 'No issues detected.')
                : self::lng('UI_APPLICATION_HEALTH_CHECK_SUMMARY_NOT_OK', 'Please follow the highlighted guidance.'),
            $statusLabel !== ''
                ? sprintf(self::lng('UI_APPLICATION_HEALTH_CHECK_LEGACY_STATUS', 'Legacy status: %s'), $statusLabel)
                : ''
        );
    }

    private static function buildLastActionCheck(array $legacy): array
    {
        $system = (isset($legacy['system']) && is_array($legacy['system'])) ? $legacy['system'] : [];
        $statusCode = strtoupper(trim((string)($system['status'] ?? '')));
        $status = self::normalizeStatus($statusCode);

        $systemData = (isset($system['data']) && is_array($system['data'])) ? $system['data'] : [];
        $detailRows = [];

        if (!empty($systemData['last_run_date'])) {
            $lastRunRaw = (string)$systemData['last_run_date'];
            $detailRows[] = [
                'type' => 'timestamp',
                'template' => self::lng('UI_APPLICATION_HEALTH_CHECK_LAST_RUN', 'Last run: %s'),
                'raw' => $lastRunRaw,
                'iso' => self::normalizeDateIso($lastRunRaw),
            ];
        }

        if (!empty($systemData['last_sent_date'])) {
            $lastSentRaw = (string)$systemData['last_sent_date'];
            $detailRows[] = [
                'type' => 'timestamp',
                'template' => self::lng('UI_APPLICATION_HEALTH_CHECK_LAST_SENT', 'Last sent: %s'),
                'raw' => $lastSentRaw,
                'iso' => self::normalizeDateIso($lastSentRaw),
            ];
        }

        if (!empty($systemData['last_run_warning'])) {
            $lastRunWarningCode = strtoupper(trim((string)$systemData['last_run_warning']));
            if ($lastRunWarningCode === 'LATE') {
                $detailRows[] = [
                    'type' => 'text',
                    'text' => self::lng('UI_APPLICATION_HEALTH_CHECK_LAST_RUN_WARNING_LATE', 'More than 24 hours since last run.'),
                ];
            } elseif ($lastRunWarningCode === 'INCOMPLETE') {
                $detailRows[] = [
                    'type' => 'text',
                    'text' => self::lng('UI_APPLICATION_HEALTH_CHECK_LAST_RUN_WARNING_INCOMPLETE', 'Sending process incomplete.'),
                ];
            } else {
                $detailRows[] = [
                    'type' => 'text',
                    'text' => sprintf(
                        self::lng('UI_APPLICATION_HEALTH_CHECK_RUN_WARNING', 'Run warning: %s'),
                        (string)$systemData['last_run_warning']
                    ),
                ];
            }
        }

        if (!empty($systemData['last_sent_warning'])) {
            $lastSentWarningCode = strtoupper(trim((string)$systemData['last_sent_warning']));
            if ($lastSentWarningCode === 'LATE') {
                $detailRows[] = [
                    'type' => 'text',
                    'text' => self::lng('UI_APPLICATION_HEALTH_CHECK_LAST_SENT_WARNING_LATE', 'More than 48 hours since last email sent.'),
                ];
            } else {
                $detailRows[] = [
                    'type' => 'text',
                    'text' => sprintf(
                        self::lng('UI_APPLICATION_HEALTH_CHECK_SENT_WARNING', 'Send warning: %s'),
                        (string)$systemData['last_sent_warning']
                    ),
                ];
            }
        }

        $details = implode('<br>', array_map(static function (array $row): string {
            if (($row['type'] ?? 'text') === 'timestamp') {
                return sprintf((string)($row['template'] ?? '%s'), (string)($row['raw'] ?? ''));
            }

            return (string)($row['text'] ?? '');
        }, $detailRows));

        $summary = ($statusCode === 'INIT')
            ? self::lng('UI_APPLICATION_HEALTH_CHECK_LAST_ACTION_INIT', 'This MailBeez installation is new, no emails have been sent yet.')
            : ($status['state'] === 'ok'
                ? self::lng('UI_APPLICATION_HEALTH_CHECK_LAST_ACTION_OK', 'The MailBeez system works like a charm!')
                : self::lng('UI_APPLICATION_HEALTH_CHECK_LAST_ACTION_NOT_OK', 'Please check your configuration.'));

        return self::buildCheck(
            'last_action',
            self::lng('UI_APPLICATION_HEALTH_CHECK_LAST_ACTION_TITLE', 'Automation'),
            $status,
            $summary,
            $details,
            ['detail_rows' => $detailRows]
        );
    }

    private static function buildSubscriptionCheck(array $legacy): ?array
    {
        $subscription = (isset($legacy['subscription']) && is_array($legacy['subscription'])) ? $legacy['subscription'] : [];
        if (empty($subscription)) {
            return null;
        }

        $subData = (isset($subscription['data']) && is_array($subscription['data'])) ? $subscription['data'] : [];
        $statusRaw = (string)($subData['status'] ?? '');
        $isPro = !empty($subscription['is_pro']);

        if ($statusRaw === '' && !$isPro && (int)($subscription['cnt'] ?? 0) === 0) {
            $statusRaw = 'WARNING';
        }

        if ($statusRaw === '') {
            $statusRaw = $isPro ? 'OK' : 'WARNING';
        }

        $status = self::normalizeStatus($statusRaw);
        $value = (isset($subData['value']) && is_array($subData['value'])) ? $subData['value'] : [];

        $details = [];
        if (!empty($value['title'])) {
            $details[] = sprintf(self::lng('UI_APPLICATION_HEALTH_CHECK_SUBSCRIPTION_TITLE', 'Plan: %s'), (string)$value['title']);
        }

        if (!empty($value['max_customers'])) {
            $details[] = sprintf(
                self::lng('UI_APPLICATION_HEALTH_CHECK_SUBSCRIPTION_CUSTOMERS', 'Customers: %s / %s'),
                (string)($legacy['cnt_distinct'] ?? '?'),
                (string)$value['max_customers']
            );
        }

        if (isset($value['expires_in']) && $value['expires_in'] !== '') {
            $details[] = sprintf(
                self::lng('UI_APPLICATION_HEALTH_CHECK_SUBSCRIPTION_EXPIRES', 'Expires in: %s days'),
                (string)$value['expires_in']
            );
        }

        if (!empty($value['message'])) {
            $details[] = sprintf(
                self::lng('UI_APPLICATION_HEALTH_CHECK_SUBSCRIPTION_MESSAGE', 'Message: %s'),
                (string)$value['message']
            );
        }

        return self::buildCheck(
            'subscription',
            self::lng('UI_APPLICATION_HEALTH_CHECK_SUBSCRIPTION_MAIN_TITLE', 'Plan'),
            $status,
            $status['state'] === 'ok'
                ? self::lng('UI_APPLICATION_HEALTH_CHECK_SUBSCRIPTION_OK', 'Plan status is healthy.')
                : self::lng('UI_APPLICATION_HEALTH_CHECK_SUBSCRIPTION_NOT_OK', 'Plan requires attention.'),
            implode('<br>', $details)
        );
    }

    private static function buildEmailCheck(array $legacy): ?array
    {

        if (!empty($legacy['status_mlbz_email_active']) && is_array($legacy['mlbz_email_data'] ?? null)) {
            $mlbz = $legacy['mlbz_email_data'];
            $status = self::normalizeStatus((string)($mlbz['status'] ?? ''));

            return self::buildCheck(
                'email',
                self::lng('UI_APPLICATION_HEALTH_CHECK_EMAIL_MLBZ_TITLE', 'Email Server'),
                $status,
                $status['state'] === 'ok'
                    ? self::lng('UI_APPLICATION_HEALTH_CHECK_EMAIL_OK', 'Integration ok.')
                    : self::lng('UI_APPLICATION_HEALTH_CHECK_EMAIL_NOT_OK', 'Please check your email integration settings.'),
                !empty($mlbz['msg'])
                    ? sprintf(self::lng('UI_APPLICATION_HEALTH_CHECK_EMAIL_MESSAGE', 'Message: %s'), (string)$mlbz['msg'])
                    : ''
            );
        }

        if (is_array($legacy['email_status'] ?? null)) {
            $emailStatus = $legacy['email_status'];
            $status = self::normalizeStatus((string)($emailStatus['status'] ?? ''));
            $emailData = (isset($emailStatus['data']) && is_array($emailStatus['data'])) ? $emailStatus['data'] : [];

            $details = [];
            if (isset($emailData['error_cnt']) && (int)$emailData['error_cnt'] > 0) {
                $details[] = sprintf(
                    self::lng('UI_APPLICATION_HEALTH_CHECK_EMAIL_ERRORS', 'Undelivered entries: %d'),
                    (int)$emailData['error_cnt']
                );
            }

            return self::buildCheck(
                'email',
                self::lng('UI_APPLICATION_HEALTH_CHECK_EMAIL_TITLE', 'Email Server'),
                $status,
                $status['state'] === 'ok'
                    ? self::lng('UI_APPLICATION_HEALTH_CHECK_EMAIL_OK', 'Integration ok.')
                    : self::lng('UI_APPLICATION_HEALTH_CHECK_EMAIL_NOT_OK', 'Please check your email integration settings.'),
                implode('<br>', $details)
            );
        }

        return null;
    }

    private static function buildCheck(string $key, string $title, array $status, string $summary = '', string $details = '', array $extra = []): array
    {
        $check = [
            'key' => $key,
            'title' => self::normalizeLegacyText(trim($title)),
            'summary' => self::normalizeLegacyText(trim($summary)),
            'details' => self::normalizeLegacyText(trim($details)),
            'state' => $status['state'],
            'severity' => $status['severity'],
        ];

        if (!empty($extra['detail_rows']) && is_array($extra['detail_rows'])) {
            $rows = [];
            foreach ($extra['detail_rows'] as $row) {
                if (!is_array($row)) {
                    continue;
                }

                $rows[] = [
                    'type' => (($row['type'] ?? 'text') === 'timestamp') ? 'timestamp' : 'text',
                    'template' => self::normalizeLegacyText((string)($row['template'] ?? '')),
                    'text' => self::normalizeLegacyText((string)($row['text'] ?? '')),
                    'raw' => self::normalizeLegacyText((string)($row['raw'] ?? '')),
                    'iso' => trim((string)($row['iso'] ?? '')),
                ];
            }

            if (!empty($rows)) {
                $check['detail_rows'] = $rows;
            }
        }

        return $check;
    }

    private static function normalizeStatus(string $statusRaw): array
    {
        $status = strtoupper(trim($statusRaw));

        if ($status === 'OK' || $status === 'TRUE' || $status === '1') {
            return [
                'state' => 'ok',
                'severity' => 'ok',
            ];
        }

        if ($status === 'INIT') {
            return [
                'state' => 'ok',
                'severity' => 'ok',
            ];
        }

        if ($status === 'WARNING' || $status === 'CHECK' || $status === '') {
            return [
                'state' => 'not_ok',
                'severity' => 'warning',
            ];
        }

        return [
            'state' => 'not_ok',
            'severity' => 'critical',
        ];
    }

    private static function legacyStatusLabel(string $status): string
    {
        if ($status === '') {
            return '';
        }

        if ($status === 'OK') {
            return self::lng('UI_APPLICATION_HEALTH_STATUS_OK', 'OK');
        }

        if ($status === 'WARNING' || $status === 'CHECK') {
            return self::lng('UI_APPLICATION_HEALTH_STATUS_WARNING', 'Warning - Please follow the guidance');
        }

        if ($status === 'ERROR') {
            return self::lng('UI_APPLICATION_HEALTH_STATUS_ERROR', 'Error - Please follow the guidance');
        }

        if ($status === 'INIT') {
            return self::lng('UI_APPLICATION_HEALTH_STATUS_INIT', 'New installation');
        }

        return $status;
    }

    private static function normalizeIssues(array $issues): array
    {
        $normalized = [];

        foreach ($issues as $issue) {
            if (is_string($issue)) {
                $issue = ['title' => $issue];
            }

            if (!is_array($issue)) {
                continue;
            }

            $title = trim((string)($issue['title'] ?? $issue['message'] ?? ''));
            if ($title === '') {
                continue;
            }

            $severityRaw = strtolower(trim((string)($issue['severity'] ?? 'warning')));
            $severity = in_array($severityRaw, ['critical', 'error', 'danger'], true) ? 'critical' : 'warning';

            $normalized[] = [
                'title' => self::normalizeLegacyText($title),
                'summary' => self::normalizeLegacyText(trim((string)($issue['summary'] ?? ''))),
                'details' => self::normalizeLegacyText(trim((string)($issue['details'] ?? ''))),
                'severity' => $severity,
            ];
        }

        return $normalized;
    }

    private static function normalizeDateIso(string $dateRaw): string
    {
        $dateRaw = trim($dateRaw);
        if ($dateRaw === '') {
            return '';
        }

        $timestamp = strtotime($dateRaw);
        if ($timestamp === false) {
            return '';
        }

        return date('c', $timestamp);
    }

    private static function normalizeLegacyText(string $value): string
    {
        $value = trim($value);
        if ($value === '' || !function_exists('mb_convert_encoding')) {
            return $value;
        }

        if (!self::looksLikeMojibake($value)) {
            return $value;
        }

        $converted = @mb_convert_encoding($value, 'UTF-8', 'ISO-8859-1');
        if (!is_string($converted) || $converted === '') {
            return $value;
        }

        return self::looksLikeMojibake($converted) ? $value : $converted;
    }

    private static function looksLikeMojibake(string $value): bool
    {
        return strpos($value, "\xC3\x83") !== false
            || strpos($value, "\xC3\x82") !== false
            || strpos($value, "\xC3\xA2") !== false;
    }
}
