<?php
namespace Components\Data\Live;

use Components\Data\Contracts\AnalyticsProvider;

class LiveAnalyticsProvider implements AnalyticsProvider
{
    public function getDashboardSummary($refresh = false): array
    {
        $result = $this->getDashboardSummaryDefaults();

        // Some legacy layers may emit HTML comments during computation; suppress incidental output
        ob_start();
        try {
            if (file_exists(MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'dashboardbeez/dashboard_statsbar.php')) {
                include_once(MH_DIR_FS_CATALOG . MH_ROOT_PATH . 'dashboardbeez/dashboard_statsbar.php');
            }

            if (class_exists('\\dashboard_statsbar')) {
                $sb = new \dashboard_statsbar();
                $data = $sb->generateData($refresh);
                $cache_timestamp_out = date('Y-m-d G:i:s', $sb->get_timestamp());

                $emailsSent   = (int)($data['cnt_sent'] ?? 0);
                $openedPercent = (int)round((float)($data['pct_opened'] ?? 0));
                $openedCount   = (int)($data['cnt_opened'] ?? 0);
                $clickPercent  = (int)round((float)($data['pct_clicked'] ?? 0));
                $clickCount    = (int)($data['cnt_clicked'] ?? 0);
                $orderPercent  = (int)round((float)($data['pct_ordered'] ?? 0));
                $orderCount    = (int)($data['cnt_orders'] ?? 0);
                $mobilePercent = (int)round((float)($data['pct_mobile'] ?? 0));
                $mobileCount   = (int)($data['cnt_mobile'] ?? 0);

                $deliveredPct  = (float)($data['pct_delivered'] ?? 0);
                $cntDelivered  = (int)($data['cnt_delivered'] ?? 0);
                $bouncedPercent = $emailsSent > 0 ? max(0, min(100, (int)round(100 - $deliveredPct))) : 0;
                $bouncedCount   = max(0, (int)$emailsSent - $cntDelivered);

                $revenue     = trim((string)($data['revenue'] ?? '0'));
                $voucherSum  = trim((string)($data['coupon_val'] ?? '0'));

                $bot = $data['beginning_of_time'] ?? null;
                $monthsAgo = 0;
                $beginningIso = '';

                if ($bot) {
                    try {
                        $start = new \DateTime($bot);
                        $now   = new \DateTime();
                        $diff  = $start->diff($now);
                        $monthsAgo = (int)($diff->y * 12 + $diff->m);
                        $beginningIso = $start->format(\DateTime::ATOM);
                    } catch (\Throwable $e2) {
                        $monthsAgo = 0;
                        $beginningIso = '';
                    }
                }

                $result = [
                    'emailsSent' => $emailsSent,
                    'monthsAgo' => $monthsAgo,
                    'beginningIso' => $beginningIso,
                    'bouncedPercent' => $bouncedPercent,
                    'bouncedCount' => $bouncedCount,
                    'openedPercent' => $openedPercent,
                    'openedCount' => $openedCount,
                    'clickPercent' => $clickPercent,
                    'clickCount' => $clickCount,
                    'orderPercent' => $orderPercent,
                    'orderCount' => $orderCount,
                    'mobilePercent' => $mobilePercent,
                    'mobileCount' => $mobileCount,
                    'revenue' => $revenue,
                    'voucherSum' => $voucherSum,
                    'bot' => $bot,
                    'cache_timestamp_out' => $cache_timestamp_out,
                ] + $this->getDashboardSummaryDefaults();
            }
        } catch (\Throwable $e) {
            // ignore
        } finally {
            ob_end_clean();
        }

        return $result;

        return $this->withEspDashboardData($result);
    }

    public function getModulePerformanceData(string $modKey = '', int $itemId = 0, array $options = []): array
    {
        if (!class_exists('\\mailbeez_analytics')) {
            return [
                'sent' => 0, 'opened' => 0, 'clicked' => 0, 'orders' => 0,
                'revenue' => '0', 'openRate' => 0, 'clickRate' => 0,
                'bounceRate' => 0, 'mobileRate' => 0, 'lastSent' => '', 'lastUpdate' => '',
            ];
        }

        $params = [];
        if ($modKey !== '') {
            $params['limit_module'] = $modKey;
        }
        if ($itemId > 0) {
            $params['limit_campaign_item_ids'] = $itemId;
        }

        if (!empty($options['timeframe'])) {
            list($start, $end) = \Components\Ui\PerformanceDashboard::resolveTimeframe($options['timeframe']);
            $params['limit_startdate_db'] = $start;
            $params['limit_enddate_db'] = $end;
        }

        // Some legacy layers may emit HTML comments during computation; suppress incidental output
        ob_start();
        try {
            $analytics = new \mailbeez_analytics($params);
            list($sent, $opened, $clicked, $delivered) = $analytics->get_engagement_data();
            list($revenue, $orders, $couponValue) = $analytics->get_orders_data();
        } finally {
            ob_end_clean();
        }

        $openRate = $sent > 0 ? ($opened / $sent) * 100 : 0;
        $clickRate = $sent > 0 ? ($clicked / $sent) * 100 : 0;
        $bounceRate = $sent > 0 ? (($sent - $delivered) / $sent) * 100 : 0;

        ob_start();
        try {
            list($mobileCount) = $analytics->get_mobile_useragent_data();
        } finally {
            ob_end_clean();
        }
        $mobileRate = $opened > 0 ? ($mobileCount / $opened) * 100 : 0;

        $lastSent = '';
        $lastUpdate = '';
        // "last update of data" is the most recent tracked activity across send/open/click/order events,
        // not merely the last time an email was sent.
        $query_last_sent_raw = "select max(date_sent) as last_sent,
                                       max(t.opened) as last_opened,
                                       max(t.clicked) as last_clicked,
                                       max(t.ordered) as last_ordered
                                    from " . TABLE_MAILBEEZ_TRACKING . " t
                                where 1 " .
            ($modKey !== '' ? " and t.module = '" . mh_db_input($modKey) . "' " : "") .
            ($itemId > 0 ? " and t.iteration = '" . (int)$itemId . "' " : "") .
            " " . str_replace('simulation', 't.simulation', MAILBEEZ_SIMULATION_SQL);
        $query_last_sent = mh_db_query($query_last_sent_raw);
        if ($row = mh_db_fetch_array($query_last_sent)) {
            if ($row['last_sent'] && $row['last_sent'] !== '0000-00-00 00:00:00') {
                try {
                    $lastSent = (new \DateTime($row['last_sent']))->format(\DateTime::ATOM);
                } catch (\Throwable $e) {
                    $lastSent = '';
                }
            }

            $lastUpdateTs = 0;
            $lastUpdateRaw = '';
            foreach (['last_sent', 'last_opened', 'last_clicked', 'last_ordered'] as $col) {
                $val = $row[$col] ?? '';
                if ($val && $val !== '0000-00-00 00:00:00') {
                    $ts = strtotime($val);
                    if ($ts !== false && $ts > $lastUpdateTs) {
                        $lastUpdateTs = $ts;
                        $lastUpdateRaw = $val;
                    }
                }
            }
            if ($lastUpdateRaw !== '') {
                try {
                    $lastUpdate = (new \DateTime($lastUpdateRaw))->format(\DateTime::ATOM);
                } catch (\Throwable $e) {
                    $lastUpdate = '';
                }
            }
        }

        return [
            'sent' => (int)$sent,
            'opened' => (int)$opened,
            'clicked' => (int)$clicked,
            'orders' => (int)$orders,
            'revenue' => trim((string)$revenue),
            'openRate' => (float)$openRate,
            'clickRate' => (float)$clickRate,
            'bounceRate' => (float)$bounceRate,
            'mobileRate' => (float)$mobileRate,
            'lastSent' => (string)$lastSent,
            'lastUpdate' => (string)$lastUpdate,
        ];
    }

    public function getAudiencePerformanceData(int $audienceId, bool $forceRefresh = false): array
    {
        $perfData = [
            'total' => 0,
        ];

        if ($audienceId > 0) {
            $audience = \Components\Models\Audience::find($audienceId);
            if ($audience) {
                $perfData['total'] = $audience->getResultCount($forceRefresh, \Components\Models\Audience::RESULT_COUNT_CACHE_TTL);

                // Surface the age of the underlying data so the dashboard badge can
                // show how old the cached count is (not time since page load). The
                // result-count cache stores the unix timestamp of its last compute.
                $rc = (array)$audience->getResultCountCache(\Components\Models\Audience::RESULT_COUNT_CACHE_TTL);
                $ts = isset($rc['ts']) ? (int)$rc['ts'] : 0;
                if ($ts > 0) {
                    $perfData['lastUpdate'] = (new \DateTime('@' . $ts))->format(\DateTime::ATOM);
                } else {
                    $perfData['lastUpdate'] = '';
                }
            }
        }

        return $perfData;
    }

    private function getDashboardSummaryDefaults(): array
    {
        return [
            'emailsSent' => 0,
            'monthsAgo' => 0,
            'beginningIso' => '',
            'bouncedPercent' => 0,
            'bouncedCount' => 0,
            'openedPercent' => 0,
            'openedCount' => 0,
            'clickPercent' => 0,
            'clickCount' => 0,
            'orderPercent' => 0,
            'orderCount' => 0,
            'mobilePercent' => 0,
            'mobileCount' => 0,
            'revenue' => '0',
            'voucherSum' => '0',
            'bot' => null,
            'cache_timestamp_out' => null,
            'espPipeline' => [
                'submitted' => 0,
                'queued' => 0,
                'attempting' => 0,
                'sent' => 0,
            ],
            'espProblems' => [
                'soft_bounces' => 0,
                'hard_bounces' => 0,
                'complaints' => 0,
                'unsubscribes' => 0,
            ],
            'espEngagement' => [
                'opens' => 0,
                'clicks' => 0,
            ],
            'espUnknownState' => 0,
            'espEventsReceived' => 0,
        ];
    }

    private function withEspDashboardData(array $result): array
    {
        $result = $result + $this->getDashboardSummaryDefaults();


        try {
            $espEvents = mh_db_query("select count(*) as cnt from " . TABLE_MAILBEEZ_ESP_EVENTS);
            if (mh_db_num_rows($espEvents) > 0) {
                $espRow = mh_db_fetch_array($espEvents);
                $result['espEventsReceived'] = (int)($espRow['cnt'] ?? 0);
            }

            $stateQuery = mh_db_query("select
                    sum(case when status='queued' then 1 else 0 end) as queued,
                    sum(case when status='attempting' then 1 else 0 end) as attempting,
                    sum(case when status='sent' then 1 else 0 end) as sent,
                    sum(soft_bounce_count) as soft_bounces,
                    sum(hard_bounce_count) as hard_bounces,
                    sum(complaint_count) as complaints,
                    sum(unsubscribe_count) as unsubscribes,
                    sum(open_count) as opens,
                    sum(click_count) as clicks
                from " . TABLE_MAILBEEZ_ESP_MESSAGE_STATE);
            if (mh_db_num_rows($stateQuery) > 0) {
                $state = mh_db_fetch_array($stateQuery);
                $result['espPipeline']['submitted'] = (int)$result['emailsSent'];
                $result['espPipeline']['queued'] = (int)($state['queued'] ?? 0);
                $result['espPipeline']['attempting'] = (int)($state['attempting'] ?? 0);
                $result['espPipeline']['sent'] = (int)($state['sent'] ?? 0);
                $result['espProblems']['soft_bounces'] = (int)($state['soft_bounces'] ?? 0);
                $result['espProblems']['hard_bounces'] = (int)($state['hard_bounces'] ?? 0);
                $result['espProblems']['complaints'] = (int)($state['complaints'] ?? 0);
                $result['espProblems']['unsubscribes'] = (int)($state['unsubscribes'] ?? 0);
                $result['espEngagement']['opens'] = (int)($state['opens'] ?? 0);
                $result['espEngagement']['clicks'] = (int)($state['clicks'] ?? 0);
            }

            $unknownQuery = mh_db_query("select count(*) as cnt
                from " . TABLE_MAILBEEZ_TRACKING . " t
                left join " . TABLE_MAILBEEZ_ESP_MESSAGE_STATE . " s on s.autoemail_id = t.autoemail_id
                where t.message_id > 0 and s.autoemail_id is null");
            if (mh_db_num_rows($unknownQuery) > 0) {
                $unknown = mh_db_fetch_array($unknownQuery);
                $result['espUnknownState'] = (int)($unknown['cnt'] ?? 0);
            }
        } catch (\Throwable $e) {
            // keep compatibility payload on DB/installation gaps
        }

        return $result;
    }
}
