<?php
namespace Analytics\Controllers\Api;

use Analytics\Lib\Response;
use Analytics\Repositories\EventDataRepository;
use Analytics\Repositories\PageDataRepository;
use Analytics\Repositories\ProjectRepository;
use Analytics\Repositories\QueryDataRepository;
use Analytics\Repositories\SnapshotRepository;
use Analytics\Services\AnalyticsFetchService;
use Analytics\Services\ExcelExportService;
use Analytics\Services\ReportBuilderService;
use Crawl\Repositories\OAuthTokenRepository;
use Crawl\Services\GoogleOAuthService;

class AnalyticsController
{
    private ProjectRepository  $projects;
    private SnapshotRepository $snapshots;
    private AnalyticsFetchService $fetcher;
    private ReportBuilderService  $reports;

    public function __construct()
    {
        $this->projects  = new ProjectRepository();
        $this->snapshots = new SnapshotRepository();
        $this->fetcher   = new AnalyticsFetchService();
        $this->reports   = new ReportBuilderService();
    }

    // ── Fetch (run tracker) ──────────────────────────────────────────────────

    public function fetchProject(int $projectId, array $body): void
    {
        ob_start();
        try {
            $project = $this->projects->find($projectId);
            if (!$project) { ob_end_clean(); Response::error('Project not found', 404); return; }

            $start  = $body['start']  ?? date('Y-m-d', strtotime('-30 days'));
            $end    = $body['end']    ?? date('Y-m-d');
            $type   = $body['period_type'] ?? 'custom';

            set_time_limit(120);
            $result = $this->fetcher->fetchProject($projectId, $project, $start, $end, $type);
            ob_end_clean();
            Response::success($result);
        } catch (\Throwable $e) {
            ob_end_clean();
            Response::error($e->getMessage(), 500);
        }
    }

    public function fetchComparison(int $projectId, array $body): void
    {
        ob_start();
        try {
            $project = $this->projects->find($projectId);
            if (!$project) { ob_end_clean(); Response::error('Project not found', 404); return; }

            $cmpStart = $body['cmp_start'] ?? '';
            $cmpEnd   = $body['cmp_end']   ?? '';
            if (!$cmpStart || !$cmpEnd) { ob_end_clean(); Response::error('cmp_start and cmp_end required', 422); return; }

            set_time_limit(180);
            $result = $this->fetcher->fetchProject($projectId, $project, $cmpStart, $cmpEnd, 'custom');
            ob_end_clean();
            Response::success($result);
        } catch (\Throwable $e) {
            ob_end_clean();
            Response::error($e->getMessage(), 500);
        }
    }

    public function fetchAll(array $body): void
    {
        ob_start();
        try {
            $projects = $this->projects->allConnected();
            $start    = $body['start'] ?? date('Y-m-d', strtotime('-30 days'));
            $end      = $body['end']   ?? date('Y-m-d');
            $type     = $body['period_type'] ?? 'custom';

            set_time_limit(600);
            $results = [];
            foreach ($projects as $p) {
                $results[] = array_merge(
                    ['project_id' => (int)$p['id'], 'business_name' => $p['business_name']],
                    $this->fetcher->fetchProject((int)$p['id'], $p, $start, $end, $type)
                );
            }
            ob_end_clean();
            Response::success(['results' => $results, 'total' => count($results)]);
        } catch (\Throwable $e) {
            ob_end_clean();
            Response::error($e->getMessage(), 500);
        }
    }

    // ── Bulk Google Account Connect ──────────────────────────────────────────

    public function bulkConnectRedirect(): void
    {
        $oauth = new GoogleOAuthService();
        if (!$oauth->isConfigured()) {
            Response::error('Google OAuth not configured in .env', 503);
            return;
        }
        $url = $oauth->buildBulkAuthUrl();
        header('Location: ' . $url);
        exit;
    }

    public function bulkConnectStatus(): void
    {
        $repo = new OAuthTokenRepository();
        $ga4  = $repo->find(0, 'ga4');
        $gsc  = $repo->find(0, 'gsc');
        Response::success([
            'connected' => (bool)$ga4,
            'email'     => $ga4['account_email'] ?? null,
            'ga4'       => $ga4  ? ['email' => $ga4['account_email'],  'expires' => $ga4['token_expires_at']]  : null,
            'gsc'       => $gsc  ? ['email' => $gsc['account_email'],  'expires' => $gsc['token_expires_at']]  : null,
        ]);
    }

    public function bulkDisconnect(): void
    {
        $repo = new OAuthTokenRepository();
        $repo->delete(0, 'ga4');
        $repo->delete(0, 'gsc');
        Response::success(['disconnected' => true]);
    }

    // ── Snapshots ────────────────────────────────────────────────────────────

    public function getSnapshot(int $projectId, array $query): void
    {
        $start = $query['start'] ?? '';
        $end   = $query['end']   ?? '';
        if (!$start || !$end) { Response::error('start and end required', 422); return; }

        $snap = $this->snapshots->find($projectId, $start, $end);
        if (!$snap) { Response::error('No snapshot for this period', 404); return; }

        $prev = $this->snapshots->previous($projectId, $start, $end);
        $project = $this->projects->find($projectId);
        Response::success([
            'snapshot'     => $snap,
            'previous'     => $prev,
            'health_score' => $project ? $this->reports->calcHealthScore($snap, $prev) : 0,
            'roas'         => $project ? $this->reports->calcRoas($snap, $project) : 0,
        ]);
    }

    public function listSnapshots(int $projectId): void
    {
        Response::success($this->snapshots->listForProject($projectId, 24));
    }

    // ── Report data ──────────────────────────────────────────────────────────

    public function getReport(int $projectId, array $query): void
    {
        $project  = $this->projects->find($projectId);
        if (!$project) { Response::error('Project not found', 404); return; }

        $start    = $query['start']    ?? date('Y-m-d', strtotime('-30 days'));
        $end      = $query['end']      ?? date('Y-m-d');
        $audience = $query['audience'] ?? 'client';

        $report = $this->reports->buildReport($projectId, $project, $start, $end, $audience);
        Response::success($report);
    }

    public function getTrend(int $projectId, array $query): void
    {
        ob_start();
        try {
            $project = $this->projects->find($projectId);
            if (!$project) { ob_end_clean(); Response::error('Project not found', 404); return; }

            $start   = $query['start']   ?? date('Y-m-d', strtotime('-30 days'));
            $end     = $query['end']     ?? date('Y-m-d');
            $metric  = $query['metric']  ?? 'sessions';
            $groupBy = $query['groupBy'] ?? 'day';

            set_time_limit(60);
            $data = $this->fetcher->fetchTrend($projectId, $project, $start, $end, $metric, $groupBy);
            ob_end_clean();
            Response::success($data);
        } catch (\Throwable $e) {
            ob_end_clean();
            Response::error($e->getMessage(), 500);
        }
    }

    public function getManagerRollup(array $query): void
    {
        $projects = $this->projects->all();
        $start    = $query['start'] ?? date('Y-m-d', strtotime('-30 days'));
        $end      = $query['end']   ?? date('Y-m-d');
        Response::success($this->reports->buildManagerRollup($projects, $start, $end));
    }

    // ── Export ───────────────────────────────────────────────────────────────

    public function exportExcel(int $projectId, array $query): void
    {
        $project  = $this->projects->find($projectId);
        if (!$project) { Response::error('Project not found', 404); return; }

        $start    = $query['start']    ?? date('Y-m-d', strtotime('-30 days'));
        $end      = $query['end']      ?? date('Y-m-d');
        $audience = $query['audience'] ?? 'client';
        $period   = "{$start} to {$end}";

        $report  = $this->reports->buildReport($projectId, $project, $start, $end, $audience);
        $svc     = new ExcelExportService();

        $tmpFile = match ($audience) {
            'business' => $svc->businessOwner([$report], $period),
            'business_owner' => $svc->businessOwner([$report], $period),
            'team'     => $svc->team($report, $period),
            default    => $svc->client([$report], $period),
        };

        $filename = "analytics_{$audience}_{$project['business_name']}_{$start}.xlsx";
        $filename = preg_replace('/[^a-z0-9_\-\.]/i', '_', $filename);
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Content-Length: ' . filesize($tmpFile));
        readfile($tmpFile);
        unlink($tmpFile);
        exit;
    }

    public function exportManagerExcel(array $query): void
    {
        $projects = $this->projects->all();
        $start    = $query['start'] ?? date('Y-m-d', strtotime('-30 days'));
        $end      = $query['end']   ?? date('Y-m-d');
        $rollup   = $this->reports->buildManagerRollup($projects, $start, $end);
        $tmpFile  = (new ExcelExportService())->managerRollup($rollup, "{$start} to {$end}");

        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment; filename="manager_rollup_' . date('Y-m-d') . '.xlsx"');
        header('Content-Length: ' . filesize($tmpFile));
        readfile($tmpFile);
        unlink($tmpFile);
        exit;
    }

    // ── Project config update ─────────────────────────────────────────────────

    public function updateConfig(int $projectId, array $body): void
    {
        $allowed = ['business_id', 'business_category', 'business_sub_category',
                    'revenue_managed', 'seo_head', 'manager_name', 'sr_analyst',
                    'onboard_date', 'brand_term_regex', 'ai_overview_event', 'lead_categories'];
        $data = array_intersect_key($body, array_flip($allowed));
        $this->projects->updateAnalyticsConfig($projectId, $data);
        Response::success(['updated' => true]);
    }

    // ── Drill-down data ──────────────────────────────────────────────────────

    public function getPageData(int $projectId, array $query): void
    {
        $snap = $this->snapshots->find($projectId, $query['start'] ?? '', $query['end'] ?? '');
        if (!$snap) { Response::success([]); return; }
        $limit  = min(500, (int)($query['limit'] ?? 200));
        $offset = (int)($query['offset'] ?? 0);
        Response::success((new PageDataRepository())->bySnapshot((int)$snap['id'], $limit, $offset));
    }

    public function getQueryData(int $projectId, array $query): void
    {
        $snap = $this->snapshots->find($projectId, $query['start'] ?? '', $query['end'] ?? '');
        if (!$snap) { Response::success([]); return; }
        $limit  = min(500, (int)($query['limit'] ?? 100));
        $offset = (int)($query['offset'] ?? 0);
        Response::success((new QueryDataRepository())->bySnapshot((int)$snap['id'], $limit, $offset));
    }

    public function getEventData(int $projectId, array $query): void
    {
        $snap = $this->snapshots->find($projectId, $query['start'] ?? '', $query['end'] ?? '');
        if (!$snap) { Response::success([]); return; }
        Response::success((new EventDataRepository())->bySnapshot((int)$snap['id']));
    }
}
