<?php

/**
 * Facebook Ads Manager – Admin Controller v1.0
 * Meta Marketing API v19.0
 */
class FbAdsAdminController
{
    private const FB_API = 'https://graph.facebook.com/v19.0';

    // ── Helpers ───────────────────────────────────────────────────────
    private function cfg(): array
    {
        return db()->query("SELECT * FROM fb_settings LIMIT 1")->fetch(\PDO::FETCH_ASSOC) ?: [];
    }

    private function redirect(string $path, string $msg = '', string $type = 'success'): never
    {
        if ($msg) $_SESSION['fb_' . $type] = $msg;
        header('Location: ' . $path);
        exit;
    }

    private function json(array $data, int $code = 200): never
    {
        http_response_code($code);
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode($data, JSON_UNESCAPED_UNICODE);
        exit;
    }

    private function isAiAvailable(): bool
    {
        try {
            return (bool) db()->query("SELECT COUNT(*) FROM ai_settings WHERE api_key!='' AND is_active=1")->fetchColumn();
        } catch (\Throwable $e) { return false; }
    }

    // ── Dashboard ─────────────────────────────────────────────────────
    public function index(): void
    {
        FbAdsLicenseGuard::check();
        FbLang::load();

        $pdo = db();
        $cfg = $this->cfg();

        $campaigns = $pdo->query("
            SELECT c.*, p.title AS product_title, p.featured_image
            FROM fb_campaigns c
            LEFT JOIN products p ON p.id = c.product_id
            ORDER BY c.created_at DESC
            LIMIT 50
        ")->fetchAll(\PDO::FETCH_ASSOC);

        $stats = [
            'total'      => (int) $pdo->query("SELECT COUNT(*) FROM fb_campaigns")->fetchColumn(),
            'active'     => (int) $pdo->query("SELECT COUNT(*) FROM fb_campaigns WHERE status='active'")->fetchColumn(),
            'spend'      => (float) $pdo->query("SELECT COALESCE(SUM(spend),0) FROM fb_campaigns")->fetchColumn(),
            'clicks'     => (int) $pdo->query("SELECT COALESCE(SUM(clicks),0) FROM fb_campaigns")->fetchColumn(),
        ];

        $isConfigured = !empty($cfg['access_token']) && !empty($cfg['ad_account_id']) && !empty($cfg['page_id']);
        $aiAvailable  = $this->isAiAvailable();

        require ROOT_PATH . '/plugins/FacebookAds/templates/dashboard.php';
    }

    // ── Create Ad Wizard ──────────────────────────────────────────────
    public function create(int $id): void
    {
        FbAdsLicenseGuard::check();
        FbLang::load();

        $cfg = $this->cfg();
        $isConfigured = !empty($cfg['access_token']) && !empty($cfg['ad_account_id']) && !empty($cfg['page_id']);

        $product = db()->prepare("SELECT * FROM products WHERE id=? AND status='active' LIMIT 1");
        $product->execute([$id]);
        $product = $product->fetch(\PDO::FETCH_ASSOC);

        if (!$product) {
            $this->redirect('/admin/facebook-ads', fbt('fb_ads.product_not_found', 'Product not found.'), 'error');
        }

        $aiAvailable = $this->isAiAvailable();

        // Facebook interest categories (common ones)
        $fbInterests = $this->getCommonInterests();

        require ROOT_PATH . '/plugins/FacebookAds/templates/create.php';
    }

    // ── Launch Ad (the core function) ─────────────────────────────────
    public function launch(): void
    {
        FbAdsLicenseGuard::check();

        $cfg = $this->cfg();
        if (empty($cfg['access_token']) || empty($cfg['ad_account_id']) || empty($cfg['page_id'])) {
            $this->json(['success' => false, 'message' => 'Facebook not configured. Go to Settings.'], 400);
        }

        $p          = $_POST;
        $productId  = (int)($p['product_id'] ?? 0);
        $name       = trim($p['campaign_name'] ?? '');
        $objective  = in_array($p['objective'] ?? '', ['OUTCOME_SALES','OUTCOME_TRAFFIC','OUTCOME_AWARENESS','OUTCOME_ENGAGEMENT'])
                      ? $p['objective'] : 'OUTCOME_SALES';
        $dailyBudget = (int)(floatval($p['daily_budget'] ?? 1) * 100); // convert to cents
        $duration   = max(1, min(90, (int)($p['duration_days'] ?? 7)));
        $adText     = trim($p['ad_text'] ?? '');
        $adHeadline = trim($p['ad_headline'] ?? '');
        $adDesc     = trim($p['ad_description'] ?? '');

        if (!$productId || !$name || !$adText) {
            $this->json(['success' => false, 'message' => 'Missing required fields.'], 422);
        }

        // Targeting
        $targeting = [
            'geo_locations' => [
                'countries' => array_filter(explode(',', trim($p['countries'] ?? $cfg['default_country']))),
            ],
            'age_min'  => max(13, min(65, (int)($p['age_min'] ?? 18))),
            'age_max'  => max(13, min(65, (int)($p['age_max'] ?? 55))),
        ];

        if (!empty($p['genders']) && in_array($p['genders'], ['1', '2'])) {
            $targeting['genders'] = [(int)$p['genders']];
        }

        if (!empty($p['interests'])) {
            $interests = json_decode($p['interests'], true);
            if (is_array($interests) && !empty($interests)) {
                $targeting['flexible_spec'] = [['interests' => $interests]];
            }
        }

        // Get product image
        $product = db()->prepare("SELECT * FROM products WHERE id=? LIMIT 1");
        $product->execute([$productId]);
        $product = $product->fetch(\PDO::FETCH_ASSOC);
        $imageUrl = $this->resolveImageUrl($product['featured_image'] ?? '');

        // Save campaign to DB (draft)
        $pdo = db();
        $pdo->prepare("
            INSERT INTO fb_campaigns
                (product_id, name, objective, daily_budget, duration_days, targeting, ad_text, ad_headline, ad_description, status)
            VALUES (?,?,?,?,?,?,?,?,?,'pending')
        ")->execute([$productId, $name, $objective, $dailyBudget, $duration, json_encode($targeting), $adText, $adHeadline, $adDesc]);
        $campaignDbId = (int) $pdo->lastInsertId();

        // ── Call Meta Marketing API ────────────────────────────────────
        $token     = $cfg['access_token'];
        $accountId = $cfg['ad_account_id'];
        $pageId    = $cfg['page_id'];
        $startTime = date('Y-m-d\TH:i:sO');
        $endTime   = date('Y-m-d\TH:i:sO', strtotime("+{$duration} days"));

        try {
            // Step 1: Create Campaign
            $campaignRes = $this->fbPost("/act_{$accountId}/campaigns", [
                'name'                => $name,
                'objective'           => $objective,
                'status'              => 'PAUSED', // نبدأ موقوفة للمراجعة
                'special_ad_categories' => '[]',
                'access_token'        => $token,
            ]);

            if (empty($campaignRes['id'])) {
                throw new \Exception('Campaign creation failed: ' . ($campaignRes['error']['message'] ?? json_encode($campaignRes)));
            }
            $fbCampaignId = $campaignRes['id'];
            $pdo->prepare("UPDATE fb_campaigns SET fb_campaign_id=? WHERE id=?")->execute([$fbCampaignId, $campaignDbId]);

            // Step 2: Create Ad Set
            $adSetRes = $this->fbPost("/act_{$accountId}/adsets", [
                'name'               => $name . ' — AdSet',
                'campaign_id'        => $fbCampaignId,
                'billing_event'      => 'IMPRESSIONS',
                'optimization_goal'  => $this->getOptimizationGoal($objective),
                'bid_strategy'       => 'LOWEST_COST_WITHOUT_CAP',
                'daily_budget'       => $dailyBudget,
                'targeting'          => json_encode($targeting),
                'start_time'         => $startTime,
                'end_time'           => $endTime,
                'status'             => 'PAUSED',
                'access_token'       => $token,
            ]);

            if (empty($adSetRes['id'])) {
                throw new \Exception('Ad Set creation failed: ' . ($adSetRes['error']['message'] ?? json_encode($adSetRes)));
            }
            $fbAdSetId = $adSetRes['id'];
            $pdo->prepare("UPDATE fb_campaigns SET fb_adset_id=? WHERE id=?")->execute([$fbAdSetId, $campaignDbId]);

            // Step 3: Upload image if local
            $imageHash = null;
            if ($imageUrl) {
                $imgRes = $this->fbPost("/act_{$accountId}/adimages", [
                    'url'          => $imageUrl,
                    'access_token' => $token,
                ]);
                $imageHash = $imgRes['images']['bytes']['hash'] ?? null;
            }

            // Step 3: Create Ad Creative
            $objectStorySpec = [
                'page_id' => $pageId,
                'link_data' => [
                    'message'     => $adText,
                    'link'        => $this->getSiteUrl() . '/product/' . ($product['slug'] ?? $productId),
                    'name'        => $adHeadline ?: $product['title'],
                    'description' => $adDesc ?: '',
                    'call_to_action' => ['type' => 'SHOP_NOW'],
                ],
            ];

            if ($imageHash) {
                $objectStorySpec['link_data']['image_hash'] = $imageHash;
            }

            $creativeRes = $this->fbPost("/act_{$accountId}/adcreatives", [
                'name'                => $name . ' — Creative',
                'object_story_spec'   => json_encode($objectStorySpec),
                'access_token'        => $token,
            ]);

            if (empty($creativeRes['id'])) {
                throw new \Exception('Creative creation failed: ' . ($creativeRes['error']['message'] ?? json_encode($creativeRes)));
            }
            $fbCreativeId = $creativeRes['id'];
            $pdo->prepare("UPDATE fb_campaigns SET fb_creative_id=? WHERE id=?")->execute([$fbCreativeId, $campaignDbId]);

            // Step 4: Create Ad
            $adRes = $this->fbPost("/act_{$accountId}/ads", [
                'name'       => $name . ' — Ad',
                'adset_id'   => $fbAdSetId,
                'creative'   => json_encode(['creative_id' => $fbCreativeId]),
                'status'     => 'PAUSED',
                'access_token' => $token,
            ]);

            if (empty($adRes['id'])) {
                throw new \Exception('Ad creation failed: ' . ($adRes['error']['message'] ?? json_encode($adRes)));
            }
            $fbAdId = $adRes['id'];

            // ✅ All steps succeeded
            $pdo->prepare("
                UPDATE fb_campaigns SET
                    fb_ad_id=?, status='active',
                    start_time=?, end_time=?
                WHERE id=?
            ")->execute([$fbAdId, $startTime, $endTime, $campaignDbId]);

            $this->json([
                'success'     => true,
                'message'     => fbt('fb_ads.campaign_created', 'Campaign created successfully! Review it in Ads Manager.'),
                'campaign_id' => $campaignDbId,
                'fb_ids'      => [
                    'campaign' => $fbCampaignId,
                    'adset'    => $fbAdSetId,
                    'creative' => $fbCreativeId,
                    'ad'       => $fbAdId,
                ],
                'ads_manager_url' => "https://www.facebook.com/adsmanager/manage/campaigns?act={$accountId}",
            ]);

        } catch (\Throwable $e) {
            $pdo->prepare("UPDATE fb_campaigns SET status='error', error_message=? WHERE id=?")->execute([$e->getMessage(), $campaignDbId]);
            $this->json(['success' => false, 'message' => $e->getMessage(), 'campaign_id' => $campaignDbId]);
        }
    }

    // ── Campaign view (stats) ─────────────────────────────────────────
    public function viewCampaign(int $id): void
    {
        FbAdsLicenseGuard::check();
        FbLang::load();
        $cfg = $this->cfg();

        $campaign = db()->prepare("
            SELECT c.*, p.title AS product_title, p.featured_image
            FROM fb_campaigns c LEFT JOIN products p ON p.id=c.product_id WHERE c.id=?
        ");
        $campaign->execute([$id]);
        $campaign = $campaign->fetch(\PDO::FETCH_ASSOC);
        if (!$campaign) { http_response_code(404); return; }
        $campaign['targeting'] = json_decode($campaign['targeting'] ?? '{}', true) ?: [];

        require ROOT_PATH . '/plugins/FacebookAds/templates/campaign_view.php';
    }

    // ── Pause / Resume / Delete ───────────────────────────────────────
    public function pauseCampaign(int $id): void
    {
        $this->updateCampaignStatus($id, 'PAUSED', 'paused');
        $this->redirect("/admin/facebook-ads/campaign/{$id}", fbt('fb_ads.msg_paused', 'Campaign paused.'));
    }

    public function resumeCampaign(int $id): void
    {
        $this->updateCampaignStatus($id, 'ACTIVE', 'active');
        $this->redirect("/admin/facebook-ads/campaign/{$id}", fbt('fb_ads.msg_resumed', 'Campaign resumed.'));
    }

    public function deleteCampaign(int $id): void
    {
        $cfg = $this->cfg();
        $campaign = db()->prepare("SELECT * FROM fb_campaigns WHERE id=?")->execute([$id]) ? null : null;
        // Mark as deleted in FB
        $stmt = db()->prepare("SELECT fb_campaign_id FROM fb_campaigns WHERE id=?");
        $stmt->execute([$id]);
        $fbId = $stmt->fetchColumn();
        if ($fbId && !empty($cfg['access_token'])) {
            $this->fbDelete("/{$fbId}", $cfg['access_token']);
        }
        db()->prepare("UPDATE fb_campaigns SET status='deleted' WHERE id=?")->execute([$id]);
        $this->redirect('/admin/facebook-ads', fbt('fb_ads.msg_deleted', 'Campaign deleted.'));
    }

    // ── Sync stats from Facebook ──────────────────────────────────────
    public function syncStats(): void
    {
        $cfg = $this->cfg();
        if (empty($cfg['access_token'])) {
            $this->json(['success' => false, 'message' => 'Not configured.']);
        }

        $active = db()->query("SELECT * FROM fb_campaigns WHERE status='active' AND fb_campaign_id IS NOT NULL")
                       ->fetchAll(\PDO::FETCH_ASSOC);

        $updated = 0;
        foreach ($active as $c) {
            try {
                $res = $this->fbGet("/{$c['fb_campaign_id']}/insights", [
                    'fields'       => 'impressions,clicks,spend',
                    'access_token' => $cfg['access_token'],
                ]);
                if (!empty($res['data'][0])) {
                    $d = $res['data'][0];
                    db()->prepare("UPDATE fb_campaigns SET impressions=?,clicks=?,spend=? WHERE id=?")
                        ->execute([(int)($d['impressions']??0),(int)($d['clicks']??0),(float)($d['spend']??0),$c['id']]);
                    $updated++;
                }
            } catch (\Throwable $e) {}
        }

        $this->json(['success' => true, 'updated' => $updated]);
    }

    // ── Settings ──────────────────────────────────────────────────────
    public function settings(): void
    {
        FbLang::load();
        $cfg = $this->cfg();
        $domain = FbAdsLicenseGuard::currentDomain();
        $aiAvailable = $this->isAiAvailable();
        require ROOT_PATH . '/plugins/FacebookAds/templates/settings.php';
    }

    public function saveSettings(): void
    {
        $p = $_POST;
        db()->prepare("
            UPDATE fb_settings SET
                access_token    = :tok,
                ad_account_id   = :acc,
                page_id         = :pid,
                pixel_id        = :pix,
                default_country = :cty,
                is_active       = :act
        ")->execute([
            ':tok' => trim($p['access_token']    ?? ''),
            ':acc' => preg_replace('/[^\d]/', '', trim($p['ad_account_id'] ?? '')),
            ':pid' => trim($p['page_id']         ?? ''),
            ':pix' => trim($p['pixel_id']        ?? ''),
            ':cty' => strtoupper(substr(trim($p['default_country'] ?? 'DZ'), 0, 3)),
            ':act' => isset($p['is_active']) ? 1 : 0,
        ]);
        $this->redirect('/admin/facebook-ads/settings', fbt('fb_ads.msg_saved', 'Settings saved.'));
    }

    public function verifyToken(): void
    {
        $token     = trim($_POST['access_token'] ?? '');
        $accountId = preg_replace('/[^\d]/', '', trim($_POST['ad_account_id'] ?? ''));

        if (!$token || !$accountId) {
            $this->json(['success' => false, 'message' => 'Access token and Ad Account ID required.']);
        }

        // Verify token by checking the ad account
        $res = $this->fbGet("/act_{$accountId}", [
            'fields'       => 'name,currency,account_status',
            'access_token' => $token,
        ]);

        if (!empty($res['id'])) {
            $status = match((int)($res['account_status'] ?? 0)) {
                1  => 'Active ✅',
                2  => 'Disabled ❌',
                9  => 'In Review ⏳',
                default => 'Unknown'
            };
            $this->json([
                'success'  => true,
                'message'  => "Connected! Account: {$res['name']} | Currency: {$res['currency']} | Status: {$status}",
                'account'  => $res,
            ]);
        } else {
            $this->json(['success' => false, 'message' => $res['error']['message'] ?? 'Invalid token or Account ID.']);
        }
    }

    public function rebindLicense(): void
    {
        $domain = trim($_POST['domain'] ?? '');
        if ($domain) {
            FbAdsLicenseGuard::bind($domain);
            $_SESSION['fb_success'] = fbt('fb_ads.msg_rebound', 'License rebound to: :d', ['d' => $domain]);
        }
        $this->redirect('/admin/facebook-ads/settings');
    }

    public function uninstall(): void
    {
        if (trim($_POST['confirm'] ?? '') !== 'DELETE') {
            $this->redirect('/admin/facebook-ads/settings', fbt('fb_ads.error_confirm', 'Type DELETE.'), 'error');
        }
        $pdo = db();
        $pdo->exec("DROP TABLE IF EXISTS fb_campaigns");
        $pdo->exec("DROP TABLE IF EXISTS fb_settings");
        $pdo->prepare("DELETE FROM plugins WHERE slug=?")->execute(['facebook-ads']);
        $this->removeLangKeys();
        $_SESSION['success'] = 'Facebook Ads uninstalled.';
        $this->redirect('/admin/plugins');
    }

    // ── Meta API helpers ──────────────────────────────────────────────
    private function fbPost(string $endpoint, array $params): array
    {
        $ch = curl_init(self::FB_API . $endpoint);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => http_build_query($params),
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_SSL_VERIFYPEER => false,
        ]);
        $res = curl_exec($ch);
        curl_close($ch);
        return json_decode($res ?: '{}', true) ?: [];
    }

    private function fbGet(string $endpoint, array $params): array
    {
        $url = self::FB_API . $endpoint . '?' . http_build_query($params);
        $ch  = curl_init($url);
        curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 20, CURLOPT_SSL_VERIFYPEER => false]);
        $res = curl_exec($ch);
        curl_close($ch);
        return json_decode($res ?: '{}', true) ?: [];
    }

    private function fbDelete(string $endpoint, string $token): void
    {
        $ch = curl_init(self::FB_API . $endpoint . '?access_token=' . $token);
        curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_CUSTOMREQUEST=>'DELETE', CURLOPT_TIMEOUT=>15, CURLOPT_SSL_VERIFYPEER=>false]);
        curl_exec($ch); curl_close($ch);
    }

    private function updateCampaignStatus(int $id, string $fbStatus, string $dbStatus): void
    {
        $cfg = $this->cfg();
        $stmt = db()->prepare("SELECT fb_campaign_id, fb_adset_id, fb_ad_id FROM fb_campaigns WHERE id=?");
        $stmt->execute([$id]);
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
        if ($row && !empty($cfg['access_token'])) {
            foreach (array_filter([$row['fb_campaign_id'], $row['fb_adset_id'], $row['fb_ad_id']]) as $fbId) {
                $this->fbPost("/{$fbId}", ['status' => $fbStatus, 'access_token' => $cfg['access_token']]);
            }
        }
        db()->prepare("UPDATE fb_campaigns SET status=? WHERE id=?")->execute([$dbStatus, $id]);
    }

    private function getOptimizationGoal(string $objective): string
    {
        return match($objective) {
            'OUTCOME_SALES'      => 'OFFSITE_CONVERSIONS',
            'OUTCOME_TRAFFIC'    => 'LINK_CLICKS',
            'OUTCOME_AWARENESS'  => 'REACH',
            'OUTCOME_ENGAGEMENT' => 'POST_ENGAGEMENT',
            default              => 'LINK_CLICKS',
        };
    }

    private function resolveImageUrl(string $img): string
    {
        if (!$img) return '';
        if (str_starts_with($img, 'http')) return $img;
        return $this->getSiteUrl() . '/' . ltrim($img, '/');
    }

    private function getSiteUrl(): string
    {
        $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
        return $scheme . '://' . ($_SERVER['HTTP_HOST'] ?? '');
    }

    private function getCommonInterests(): array
    {
        return [
            ['id' => '6003107902433', 'name' => 'Shopping'],
            ['id' => '6003397425735', 'name' => 'Online shopping'],
            ['id' => '6003467736159', 'name' => 'Fashion'],
            ['id' => '6003145475396', 'name' => 'Beauty'],
            ['id' => '6003195797498', 'name' => 'Technology'],
            ['id' => '6003415325826', 'name' => 'Sports'],
            ['id' => '6003108195963', 'name' => 'Cooking'],
            ['id' => '6003267613044', 'name' => 'Travel'],
            ['id' => '6003376321876', 'name' => 'Health & wellness'],
            ['id' => '6003257402054', 'name' => 'Gaming'],
            ['id' => '6003482897785', 'name' => 'Parenting'],
            ['id' => '6003272635636', 'name' => 'Home decoration'],
        ];
    }

    private function removeLangKeys(): void
    {
        foreach (['en','ar'] as $code) {
            $file = ROOT_PATH.'/lang/'.$code.'.json';
            if(!is_file($file)) continue;
            $data=json_decode(file_get_contents($file),true)??[];
            foreach(array_keys($data) as $k){if(str_starts_with($k,'fb_ads.'))unset($data[$k]);}
            ksort($data);
            file_put_contents($file,json_encode($data,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
        }
    }

    // ── verifyLicense ─────────────────────────────────────────────────
    public function verifyLicense(): void
    {
        header('Content-Type: application/json; charset=utf-8');
        $key = trim($_POST['license_key'] ?? '');
        if (!$key) { echo json_encode(['success'=>false,'message'=>'أدخل كود الترخيص.']); exit; }

        if (!class_exists('PluginLicenseGuard')) {
            require_once ROOT_PATH . '/plugins/FacebookAds/PluginLicenseGuard.php';
        }

        $ping = PluginLicenseGuard::ping('facebook-ads', $key);

        if ($ping === null) {
            echo json_encode(['success'=>false,'message'=>'تعذّر الاتصال بخادم الترخيص.']);
            exit;
        }

        if (($ping['action'] ?? 'block') !== 'allow') {
            $msg = match($ping['status'] ?? '') {
                'violation'     => 'مرتبط بدومين آخر: ' . ($ping['domain_bound'] ?? ''),
                'expired'       => 'انتهت صلاحية الترخيص.',
                'disabled'      => 'الترخيص معطّل.',
                'invalid'       => 'كود الترخيص غير صالح.',
                default         => $ping['message'] ?? 'خطأ.',
            };
            echo json_encode(['success'=>false,'message'=>$msg]);
            exit;
        }

        PluginLicenseGuard::clearCache('facebook-ads', $key);
        db()->prepare("UPDATE fb_settings SET license_key=?, license_domain=NULL")->execute([$key]);

        $bound   = $ping['domain_bound'] ?? PluginLicenseGuard::currentDomain();
        $expires = $ping['expires'] ?? null;
        $expAr   = $expires ? 'ينتهي: '.$expires : 'مدى الحياة';
        echo json_encode([
            'success' => true,
            'message' => "✅ ترخيص صالح | {$expAr} | مرتبط بـ: {$bound}",
        ]);
        exit;
    }

}