<?php

namespace App\Services;

use App\Helpers\LanguageHelper;
use App\Helpers\ZohoHelper;
use App\Models\Franchisee;
use App\Models\Setting;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

/**
 * Resolves a franchisee's UTM-campaign languages from Zoho CRM (Franchisee_Campaigns),
 * which drive the per-language translation tabs for templates and the message flow.
 */
class FranchiseeCampaignService
{
    /**
     * Distinct UTM-campaign languages for a franchisee, as [['code'=>..,'name'=>..]].
     * Cached 6h; falls back to the franchisee's own language when Zoho returns none.
     */
    public function languagesFor(Franchisee $franchisee, bool $fresh = false): array
    {
        $zoho = $this->zohoLanguages($franchisee, $fresh);

        // Only the (expensive) Zoho result is cached. The no-campaign fallback — the
        // franchisee's SETTING language — is resolved FRESH every call, so changing the
        // language in Settings reflects immediately instead of being masked for 6h.
        return !empty($zoho) ? $zoho : [$this->fallbackLanguage($franchisee)];
    }

    /** Distinct languages from the franchisee's Zoho campaigns ([] if none). Cached 6h. */
    private function zohoLanguages(Franchisee $franchisee, bool $fresh = false): array
    {
        $key = "franchisee_campaign_langs_v2_{$franchisee->id}";
        if ($fresh) {
            Cache::forget($key);
        }

        return Cache::remember($key, now()->addHours(6), function () use ($franchisee) {
            $field = config('services.zoho.campaign_language_field');
            $langs = [];

            foreach ($this->fetchRaw($franchisee) as $record) {
                $raw = data_get($record, $field);
                // A Zoho lookup/picklist field can arrive as an object {id,name}.
                if (is_array($raw)) {
                    $raw = $raw['name'] ?? $raw['value'] ?? null;
                }
                $norm = LanguageHelper::normalizeToCodeName(is_scalar($raw) ? (string) $raw : '');
                if ($norm) {
                    $langs[$norm['code']] = $norm; // dedupe by code
                }
            }

            return array_values($langs);
        });
    }

    /** Raw Zoho campaign records for the franchisee (best-effort; [] on any error). */
    public function fetchRaw(Franchisee $franchisee): array
    {
        $accountId = $franchisee->zoho_franchise_id ?: $franchisee->crm_record_id;
        if (empty($accountId)) {
            return [];
        }

        try {
            $module = config('services.zoho.campaign_module');
            $accountField = config('services.zoho.campaign_account_field');

            $response = ZohoHelper::zohoRequest('get', "{$module}/search", [
                'criteria' => "({$accountField}:equals:{$accountId})",
            ]);

            return $response['data'] ?? [];
        } catch (\Throwable $e) {
            Log::warning('Franchisee campaign fetch failed', [
                'franchisee_id' => $franchisee->id,
                'error' => $e->getMessage(),
            ]);
            return [];
        }
    }

    /**
     * Diagnostic: the exact request + raw response (or error), so the real campaign field
     * names / scope issues can be seen against live data.
     */
    public function debug(Franchisee $franchisee): array
    {
        $accountId = $franchisee->zoho_franchise_id ?: $franchisee->crm_record_id;
        $module = config('services.zoho.campaign_module');
        $accountField = config('services.zoho.campaign_account_field');
        $criteria = "({$accountField}:equals:{$accountId})";

        $out = [
            'account_id' => $accountId,
            'module' => $module,
            'criteria' => $criteria,
            'base_url' => config('services.zoho.base_url'),
            'language_field' => config('services.zoho.campaign_language_field'),
        ];

        try {
            $resp = ZohoHelper::zohoRequest('get', "{$module}/search", ['criteria' => $criteria]);
            $out['record_count'] = count($resp['data'] ?? []);
            $out['records'] = $resp['data'] ?? [];
        } catch (\Throwable $e) {
            $out['error'] = $e->getMessage();
        }

        $out['languages'] = $this->languagesFor($franchisee, true); // also refreshes the 6h cache

        return $out;
    }

    private function fallbackLanguage(Franchisee $franchisee): array
    {
        // No UTM campaigns → use the franchisee's SETTING language (general_settings.language_code),
        // then the franchisee.language column, then English.
        $setting = Setting::where('franchisee_id', $franchisee->id)->first();
        $code = data_get($setting, 'general_settings.language_code')
            ?: ($franchisee->language ?: 'en');

        return LanguageHelper::normalizeToCodeName(strtolower((string) $code))
            ?? ['code' => 'en', 'name' => 'English'];
    }
}
