<?php

namespace App\Http\Controllers\Admin;

use App\Helpers\ApiResponse;
use App\Helpers\LanguageHelper;
use App\Helpers\TranslationHelper;
use App\Http\Controllers\Controller;
use App\Models\WhatsappTemplate;
use App\Services\WhatsappCloudService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;

class WhatsappTemplateController extends Controller
{
    public function __construct(
        private WhatsappCloudService $whatsapp,
        private \App\Services\FranchiseeCampaignService $campaigns
    ) {
    }

    /**
     * Profanity / abusive-language gate. Proxies the message body to the moderation
     * service and returns { pass, reason } so the editor can block submission before
     * the template is sent to Meta. Fails open (pass=true) if the service is unreachable
     * so a moderation outage never hard-blocks template creation.
     */
    public function checkMessage(Request $request)
    {
        try {
            $message = (string) $request->input('message', '');
            if (trim($message) === '') {
                return ApiResponse::success(['pass' => true, 'reason' => null]);
            }

            $url = config('services.moderation.url');
            if (empty($url)) {
                return ApiResponse::success(['pass' => true, 'reason' => null]);
            }

            $response = Http::withOptions(['verify' => false])
                ->timeout((int) config('services.moderation.timeout', 20))
                ->post($url, ['message' => $message]);

            if ($response->failed()) {
                Log::warning('Moderation check failed; allowing through.', [
                    'status' => $response->status(),
                    'body' => $response->body(),
                ]);
                return ApiResponse::success(['pass' => true, 'reason' => null]);
            }

            $data = $response->json();

            return ApiResponse::success([
                'pass' => (bool) ($data['pass'] ?? true),
                'reason' => $data['reason'] ?? null,
            ]);
        } catch (\Throwable $e) {
            Log::warning('Moderation check errored; allowing through.', ['error' => $e->getMessage()]);
            return ApiResponse::success(['pass' => true, 'reason' => null]);
        }
    }

    /**
     * Super admin manages the global template (franchisee_id = null).
     * Everyone else is scoped to their own franchisee.
     */
    private function isSuperAdmin($auth): bool
    {
        return $auth->role === 'super_admin';
    }

    private function scopeFranchiseeId($auth): ?string
    {
        return $this->isSuperAdmin($auth) ? null : $auth->franchisee_id;
    }

    /**
     * List templates visible to the current user.
     * - super admin: ALL global templates (they can create many; one is the default)
     * - tenant: their single template (if any) + the global default for reference
     */
    public function index()
    {
        try {
            $auth = Auth::user();

            if ($this->isSuperAdmin($auth)) {
                $templates = WhatsappTemplate::query()
                    ->where('is_global', true)
                    ->where('type', WhatsappTemplate::TYPE_WELCOME)
                    ->orderByDesc('is_default')
                    ->orderByDesc('created_at')
                    ->get();

                // Pull live PENDING / APPROVED / REJECTED state from Meta before returning.
                $this->syncStatusesFromMeta($templates);

                return ApiResponse::success([
                    'templates' => $templates->values(),
                ], 'WhatsApp templates fetched successfully');
            }

            // Franchisee: the admin's DEFAULT template (read-only source) + the franchisee's
            // own per-language rows (their translations of it). Other admin templates are hidden.
            $global = WhatsappTemplate::query()
                ->where('is_global', true)
                ->where('type', WhatsappTemplate::TYPE_WELCOME)
                ->where('is_default', true)
                ->get();

            $own = WhatsappTemplate::query()
                ->where('franchisee_id', $auth->franchisee_id)
                ->where('type', WhatsappTemplate::TYPE_WELCOME)
                ->get();

            // Refresh live statuses first, then only expose the default if it's APPROVED.
            $this->syncStatusesFromMeta($global->concat($own));
            $global = $global
                ->filter(fn($t) => $t->status === WhatsappTemplate::STATUS_APPROVED)
                ->values();

            // UTM-campaign languages drive the translation tabs in the editor.
            $languages = [];
            try {
                if ($auth->franchisee) {
                    $languages = $this->campaigns->languagesFor($auth->franchisee);
                }
            } catch (\Throwable $e) {
                $languages = [];
            }

            return ApiResponse::success([
                'global' => $global,
                'own' => $own->values(),
                'languages' => $languages,
            ], 'WhatsApp templates fetched successfully');
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    public function show($id)
    {
        try {
            $auth = Auth::user();
            $template = $this->findScoped($auth, $id);

            return ApiResponse::success($template, 'WhatsApp template fetched successfully');
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    /**
     * Create a welcome template and submit it to Meta for review.
     * Super admin may create multiple global templates; a franchisee may have only one.
     */
    public function store(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), $this->rules());
            if ($validator->fails()) {
                return ApiResponse::error($validator->errors()->first(), Response::HTTP_UNPROCESSABLE_ENTITY);
            }

            if ($exampleError = $this->exampleError($request)) {
                return ApiResponse::error($exampleError, Response::HTTP_UNPROCESSABLE_ENTITY);
            }

            if ($contentError = $this->contentError($request)) {
                return ApiResponse::error($contentError, Response::HTTP_UNPROCESSABLE_ENTITY);
            }

            $auth = Auth::user();
            $franchiseeId = $this->scopeFranchiseeId($auth);
            $isGlobal = $this->isSuperAdmin($auth);

            $components = $this->whatsapp->buildComponents($request->only([
                'header_text', 'body_text', 'footer_text', 'buttons', 'body_examples',
            ]));

            if ($isGlobal) {
                // Super admin authors a global template (existing behaviour).
                $sourceTemplateId = null;
                $metaName = $this->globalBaseName($request->input('label'));
                $language = $request->input('language', 'en_US');
                $category = $request->input('category', 'UTILITY');
            } else {
                // Franchisee: a per-language translation of an admin template. Name is
                // auto-derived ({base}_{franchise}_{lang}); one per (franchisee, source, language).
                $sourceTemplateId = $request->input('source_template_id');
                $source = $sourceTemplateId ? WhatsappTemplate::find($sourceTemplateId) : null;

                $norm = LanguageHelper::normalizeToCodeName($request->input('language', 'en')) ?? ['code' => 'en'];
                $language = LanguageHelper::codeToMetaLocale($norm['code']);

                $exists = WhatsappTemplate::query()
                    ->where('type', WhatsappTemplate::TYPE_WELCOME)
                    ->where('franchisee_id', $franchiseeId)
                    ->where('source_template_id', $sourceTemplateId)
                    ->where('language', $language)
                    ->exists();
                if ($exists) {
                    return ApiResponse::error(
                        'You already have a template for this language — edit it instead.',
                        Response::HTTP_CONFLICT
                    );
                }

                // The franchisee field already holds the full Meta name (pre-filled as
                // {source}_{franchise}_{lang}); use it verbatim, just guaranteeing uniqueness.
                $metaName = $this->uniqueMetaName($this->globalBaseName($request->input('label')));
                $category = $source->category ?? $request->input('category', 'UTILITY');
            }

            // Submit to Meta first; only persist if the submission is accepted.
            $meta = $this->whatsapp->createMessageTemplate($metaName, $language, $category, $components);

            $template = WhatsappTemplate::create([
                'franchisee_id' => $franchiseeId,
                'source_template_id' => $sourceTemplateId,
                'is_global' => $isGlobal,
                'type' => WhatsappTemplate::TYPE_WELCOME,
                'label' => $request->input('label'),
                'meta_name' => $metaName,
                'language' => $language,
                'category' => $category,
                'header_text' => $request->input('header_text'),
                'body_text' => $request->input('body_text'),
                'footer_text' => $request->input('footer_text'),
                'buttons' => $request->input('buttons'),
                'components' => $components,
                'meta_template_id' => $meta['id'] ?? null,
                'status' => $this->mapMetaStatus($meta['status'] ?? 'PENDING'),
                'created_by' => $auth->id,
            ]);

            return ApiResponse::success($template, 'WhatsApp template submitted to Meta for approval', Response::HTTP_CREATED);
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    /**
     * Edit a template. Meta does not allow editing a template that is pending or
     * approved, so editing is only permitted for draft/rejected templates and
     * resubmits a fresh review.
     */
    public function update(Request $request, $id)
    {
        try {
            $validator = Validator::make($request->all(), $this->rules());
            if ($validator->fails()) {
                return ApiResponse::error($validator->errors()->first(), Response::HTTP_UNPROCESSABLE_ENTITY);
            }

            if ($exampleError = $this->exampleError($request)) {
                return ApiResponse::error($exampleError, Response::HTTP_UNPROCESSABLE_ENTITY);
            }

            if ($contentError = $this->contentError($request)) {
                return ApiResponse::error($contentError, Response::HTTP_UNPROCESSABLE_ENTITY);
            }

            $auth = Auth::user();
            $template = $this->findScoped($auth, $id);

            if (!in_array($template->status, [WhatsappTemplate::STATUS_DRAFT, WhatsappTemplate::STATUS_REJECTED], true)) {
                return ApiResponse::error(
                    'Only draft or rejected templates can be edited. Delete this one to create a new template.',
                    Response::HTTP_CONFLICT
                );
            }

            $components = $this->whatsapp->buildComponents($request->only([
                'header_text', 'body_text', 'footer_text', 'buttons', 'body_examples',
            ]));
            $language = $request->input('language', $template->language);
            $category = $request->input('category', $template->category);

            // Determine the target Meta name.
            // - Super admin: allow renaming from the label (e.g. resubmit a rejected one).
            // - Franchisee: the name is auto-derived ({base}_{franchise}_{lang}) and fixed;
            //   keep it as-is so the language suffix isn't lost.
            // The name field holds the full Meta name (for both admin and franchisee) — rename
            // if it changed, after confirming it's free.
            $targetName = $template->meta_name;
            $newName = $this->globalBaseName($request->input('label'));
            if ($newName !== $template->meta_name) {
                if ($this->metaNameTaken($newName)) {
                    return ApiResponse::error(
                        "\"{$newName}\" is already taken. Please choose a different name.",
                        Response::HTTP_CONFLICT
                    );
                }
                $targetName = $newName;
            }

            // Resubmit to Meta. If the name is unchanged and the template already exists on
            // Meta, EDIT it in place — deleting + recreating the same name+language hits Meta's
            // "content is being deleted" race. Only a rename needs delete + create (new name).
            if ($targetName === $template->meta_name && $template->meta_template_id) {
                try {
                    $meta = $this->whatsapp->editMessageTemplate($template->meta_template_id, $category, $components);
                } catch (\Throwable $editError) {
                    // Stale id (the Meta template was deleted) → recreate, suffixing the name
                    // if Meta still has it "being deleted".
                    [$targetName, $meta] = $this->createMetaTemplate($targetName, $language, $category, $components);
                }
            } else {
                try {
                    $this->whatsapp->deleteMessageTemplate($template->meta_name);
                } catch (\Throwable $ignore) {
                    // Template may not exist on Meta's side yet; safe to ignore.
                }
                [$targetName, $meta] = $this->createMetaTemplate($targetName, $language, $category, $components);
            }

            $template->update([
                'label' => $request->input('label'),
                'meta_name' => $targetName,
                'language' => $language,
                'category' => $category,
                'header_text' => $request->input('header_text'),
                'body_text' => $request->input('body_text'),
                'footer_text' => $request->input('footer_text'),
                'buttons' => $request->input('buttons'),
                'components' => $components,
                'meta_template_id' => $meta['id'] ?? $template->meta_template_id,
                'status' => $this->mapMetaStatus($meta['status'] ?? 'PENDING'),
                'rejected_reason' => null,
                'approved_at' => null,
            ]);

            return ApiResponse::success($template, 'WhatsApp template resubmitted to Meta for approval');
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    public function destroy($id)
    {
        try {
            $auth = Auth::user();
            $template = $this->findScoped($auth, $id);

            try {
                $this->whatsapp->deleteMessageTemplate($template->meta_name);
            } catch (\Throwable $ignore) {
                // Already gone on Meta's side — proceed with local delete.
            }

            $template->delete();

            return ApiResponse::success(null, 'WhatsApp template deleted successfully');
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    /**
     * Mark a template as the default.
     * - super admin: picks which global template is the platform default (only one).
     * - franchisee: marks their own approved template as default (used instead of global).
     */
    public function setDefault(Request $request, $id)
    {
        try {
            $auth = Auth::user();
            $template = $this->findScoped($auth, $id);
            $makeDefault = $request->boolean('is_default', true);

            if ($makeDefault && !$template->isUsable()) {
                return ApiResponse::error('Only an approved template can be set as default.', Response::HTTP_CONFLICT);
            }

            if ($this->isSuperAdmin($auth)) {
                // A platform must always have one active default — don't allow turning off
                // the last one (the franchisees' fallback depends on it).
                if (!$makeDefault) {
                    $anotherDefault = WhatsappTemplate::query()
                        ->where('is_global', true)
                        ->where('type', WhatsappTemplate::TYPE_WELCOME)
                        ->where('id', '!=', $template->id)
                        ->where('is_default', true)
                        ->exists();
                    if (!$anotherDefault) {
                        return ApiResponse::error(
                            'At least one template must stay active as the default. Set another template as default instead.',
                            Response::HTTP_CONFLICT
                        );
                    }
                }

                // Only one global template can be the platform default at a time.
                if ($makeDefault) {
                    WhatsappTemplate::query()
                        ->where('is_global', true)
                        ->where('type', WhatsappTemplate::TYPE_WELCOME)
                        ->where('id', '!=', $template->id)
                        ->update(['is_default' => false]);
                }

                $template->update(['is_default' => $makeDefault]);

                $message = $makeDefault
                    ? 'This is now the platform default welcome template for all franchisees.'
                    : 'This template is no longer the platform default.';

                return ApiResponse::success($template, $message);
            }

            $template->update(['is_default' => $makeDefault]);

            $message = $makeDefault
                ? 'This template is now your default welcome message.'
                : 'Reverted to the platform default welcome template.';

            return ApiResponse::success($template, $message);
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    /**
     * Live availability check for a template name (used by the create form while typing).
     * Returns the Meta name that would actually be used and whether the exact derived
     * name is free across BOTH our database and Meta's shared WABA.
     */
    public function checkName(Request $request)
    {
        try {
            $auth = Auth::user();
            $isGlobal = $this->isSuperAdmin($auth);
            $franchiseeId = $this->scopeFranchiseeId($auth);

            // Template being edited (if any) so we don't flag its own name as taken.
            // (Name checking is the super-admin authoring path; franchisee names are
            // auto-derived as {base}_{franchise}_{lang}, so no one-per-franchisee guard.)
            $editId = $request->input('id');
            $editing = $editId ? $this->findScoped($auth, $editId) : null;

            $label = trim((string) $request->input('label', ''));
            if ($label === '') {
                return ApiResponse::success([
                    'available' => false,
                    'meta_name' => null,
                    'message' => 'Enter a template name.',
                ], 'Name checked');
            }

            $base = $this->globalBaseName($label);

            // When editing and the name is unchanged, it's the same template — always available.
            $available = ($editing && $editing->meta_name === $base)
                ? true
                : !$this->metaNameTaken($base);

            return ApiResponse::success([
                'available' => $available,
                'meta_name' => $base,
                'message' => $available
                    ? 'Available.'
                    : "\"{$base}\" is already taken. Please choose a different name.",
            ], 'Name checked');
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    /**
     * AI-translate the header/body/footer into a language so a franchisee can translate a
     * template before submitting it to Meta. {{variables}} are protected so they survive
     * the translation. Stateless — operates on the posted text, returns the translation.
     */
    public function translateContent(Request $request, TranslationHelper $translator)
    {
        try {
            $norm = LanguageHelper::normalizeToCodeName((string) $request->input('language', ''));
            if (!$norm) {
                return ApiResponse::error('Choose a language to translate into.', Response::HTTP_UNPROCESSABLE_ENTITY);
            }

            // Replace {{var}} with a placeholder the translator won't alter, restore after.
            $store = [];
            $protect = function (?string $text) use (&$store) {
                if (!filled($text)) {
                    return $text;
                }
                return preg_replace_callback('/\{\{\s*[a-zA-Z0-9_]+\s*\}\}/', function ($m) use (&$store) {
                    $token = '{{__' . count($store) . '__}}';
                    $store[$token] = $m[0];
                    return $token;
                }, $text);
            };

            $fields = [];
            foreach (['header_text', 'body_text', 'footer_text'] as $key) {
                $value = trim((string) $request->input($key, ''));
                if ($value !== '') {
                    $fields[$key] = $protect($value);
                }
            }

            $translated = !empty($fields) ? $translator->translate($fields, $norm['name']) : [];
            $restore = fn($t) => filled($t) ? strtr($t, $store) : ($t ?? '');

            return ApiResponse::success([
                'header_text' => $restore($translated['header_text'] ?? ''),
                'body_text' => $restore($translated['body_text'] ?? ''),
                'footer_text' => $restore($translated['footer_text'] ?? ''),
            ], 'Translated');
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    /**
     * Validation rules shared by store/update.
     */
    private function rules(): array
    {
        return [
            'label' => 'required|string|max:120',
            'language' => 'nullable|string|max:10',
            'source_template_id' => 'nullable|string',
            'category' => 'nullable|in:UTILITY,MARKETING,AUTHENTICATION',
            'header_text' => 'nullable|string|max:60',
            'body_text' => 'required|string|max:1024',
            'footer_text' => 'nullable|string|max:60',
            'buttons' => 'nullable|array',
            'body_examples' => 'nullable|array',
            'body_examples.*' => 'nullable|string|max:255',
        ];
    }

    /**
     * Meta auto-rejects a template if any {{n}} variable in the body has no sample
     * value. Validate up front so we fail fast instead of round-tripping a rejection.
     */
    private function exampleError(Request $request): ?string
    {
        preg_match_all('/\{\{\s*(\d+)\s*\}\}/', (string) $request->input('body_text', ''), $matches);
        $variableCount = count(array_unique($matches[1] ?? []));

        $examples = array_values(array_filter(
            array_map('strval', (array) $request->input('body_examples', [])),
            fn($v) => $v !== ''
        ));

        if ($variableCount > 0 && count($examples) < $variableCount) {
            return "Your message uses {$variableCount} variable(s). Provide a sample value for each so Meta can review it.";
        }

        return null;
    }

    /**
     * Mirror of the front-end content guards so the same Meta rejection causes are
     * caught even if the API is called directly. Returns the first problem found.
     */
    private function contentError(Request $request): ?string
    {
        $header = trim((string) $request->input('header_text', ''));
        $body = (string) $request->input('body_text', '');
        $footer = trim((string) $request->input('footer_text', ''));

        $letters = static fn(string $s): int => preg_match_all('/\p{L}/u', $s);
        $hasVar = static fn(string $s): bool => (bool) preg_match('/\{\{\s*\d+\s*\}\}/', $s);

        // Header: single line, at most one variable, real text if present.
        if ($header !== '') {
            if (preg_match('/[\r\n\t]/', $header)) {
                return 'The header must be a single line without tabs or line breaks.';
            }
            if (preg_match_all('/\{\{\s*\d+\s*\}\}/', $header) > 1) {
                return 'The header can contain at most one variable.';
            }
            if ($letters($header) < 1) {
                return 'The header needs real text — symbol-only content gets rejected by Meta.';
            }
        }

        // Body: meaningful text, sane whitespace, valid variable placement.
        if ($letters($body) < 3) {
            return 'Write a real message body — at least 3 letters. Symbol-only text gets rejected by Meta.';
        }
        if (preg_match('/\t/', $body) || preg_match('/ {4,}/', $body) || preg_match('/\n{3,}/', $body)) {
            return 'Remove tabs and long runs of spaces or blank lines from the body — Meta will reject it.';
        }
        if ($bodyVarError = $this->bodyVariableError($body)) {
            return $bodyVarError;
        }

        // Footer: single line, no variables, real text if present.
        if ($footer !== '') {
            if (preg_match('/[\r\n\t]/', $footer)) {
                return 'The footer must be a single line without tabs or line breaks.';
            }
            if ($hasVar($footer)) {
                return 'Variables are not allowed in the footer.';
            }
            if ($letters($footer) < 1) {
                return 'The footer needs real text — symbol-only content gets rejected by Meta.';
            }
        }

        return null;
    }

    /**
     * Body variables must start at {{1}}, run in order with no gaps, not sit at the
     * very start/end, and not be placed back-to-back — all are hard Meta rejections.
     */
    private function bodyVariableError(string $body): ?string
    {
        preg_match_all('/\{\{\s*(\d+)\s*\}\}/', $body, $matches);
        $nums = array_map('intval', $matches[1] ?? []);
        if (empty($nums)) {
            return null;
        }

        $ordered = array_values(array_unique($nums));
        sort($ordered);
        foreach ($ordered as $i => $n) {
            if ($n !== $i + 1) {
                return 'Number variables in order starting at {{1}} with no gaps (e.g. {{1}}, {{2}}).';
            }
        }

        $trimmed = trim($body);
        if (preg_match('/^\{\{\s*\d+\s*\}\}/', $trimmed)) {
            return "The message can't start with a variable — add text before {{1}}.";
        }
        if (preg_match('/\{\{\s*\d+\s*\}\}$/', $trimmed)) {
            return "The message can't end with a variable — add text after it.";
        }
        if (preg_match('/\}\}\s*\{\{/', $body)) {
            return "Two variables can't be next to each other — put text between them.";
        }

        return null;
    }

    /**
     * Fetch a template the current user is allowed to manage, or 404/403.
     */
    private function findScoped($auth, $id): WhatsappTemplate
    {
        $template = WhatsappTemplate::findOrFail($id);

        if ($this->isSuperAdmin($auth)) {
            // Super admin manages the global template only.
            abort_unless($template->is_global, Response::HTTP_FORBIDDEN, 'Not allowed to manage this template.');
        } else {
            abort_unless($template->franchisee_id === $auth->franchisee_id, Response::HTTP_FORBIDDEN, 'Not allowed to manage this template.');
        }

        return $template;
    }

    /**
     * The Meta template name is the typed label, slugified ([a-z0-9_]). Uniqueness is
     * NOT auto-suffixed — the create form's live availability check tells the user if a
     * name is taken so they can choose a different one.
     */
    private function buildMetaName(bool $isGlobal, ?string $franchiseeId, ?string $label = null): string
    {
        return $this->globalBaseName($label);
    }

    /**
     * The base Meta name derived from a global template's label (before any uniqueness suffix).
     * Uses the typed name as-is (lowercased, spaces/punctuation collapsed to underscores) so
     * "Test" becomes "test" — no automatic prefixing.
     */
    private function globalBaseName(?string $label): string
    {
        $slug = preg_replace('/[^a-z0-9_]/', '', Str::lower(Str::slug((string) $label, '_')));

        return $slug !== '' ? $slug : 'template';
    }

    /**
     * Create a Meta template, working around the async-deletion race. If the name+language
     * is still "being deleted" (or already exists) on Meta, retry under a numbered suffix.
     * Returns [finalMetaName, metaResponse].
     */
    private function createMetaTemplate(string $name, string $language, string $category, array $components): array
    {
        $base = $name;
        $lastError = null;

        for ($attempt = 0; $attempt < 4; $attempt++) {
            try {
                return [$name, $this->whatsapp->createMessageTemplate($name, $language, $category, $components)];
            } catch (\Throwable $e) {
                $lastError = $e;
                $msg = strtolower($e->getMessage());
                $recoverable = str_contains($msg, 'being deleted')
                    || str_contains($msg, 'already exists')
                    || str_contains($msg, 'already been created');
                if (!$recoverable) {
                    throw $e;
                }
                $name = $base . '_' . ($attempt + 2); // base_2, base_3, …
            }
        }

        throw $lastError;
    }

    /** Slugified franchise name for franchisee Meta template names. */
    private function franchiseeSlug($auth): string
    {
        $name = $auth->franchisee?->name ?? 'franchise';
        $slug = preg_replace('/[^a-z0-9_]/', '', Str::lower(Str::slug($name, '_')));

        return $slug !== '' ? $slug : 'franchise';
    }

    /**
     * Ensure the Meta name is unique across our records (incl. soft-deleted) AND Meta's
     * shared WABA — Meta may still hold a name that no longer exists in our database.
     * Appends a numeric suffix on clash.
     */
    private function uniqueMetaName(string $base): string
    {
        $base = substr($base, 0, 480);
        $name = $base;
        $i = 1;

        while ($this->metaNameTaken($name)) {
            $name = $base . '_' . $i;
            $i++;
        }

        return $name;
    }

    /**
     * Whether a Meta name is already in use, either locally (incl. soft-deleted) or on
     * Meta's WABA. If Meta is unreachable we fall back to the local check rather than
     * blocking creation outright.
     */
    private function metaNameTaken(string $name): bool
    {
        if (WhatsappTemplate::withTrashed()->where('meta_name', $name)->exists()) {
            return true;
        }

        try {
            return $this->whatsapp->templateExistsOnMeta($name);
        } catch (\Throwable $e) {
            return false;
        }
    }

    /**
     * Refresh the stored status of the given templates from Meta in one sweep, so the
     * list always reflects the live PENDING / APPROVED / REJECTED state instead of the
     * value captured at submission time. Best-effort: if Meta is unreachable the stored
     * statuses are kept.
     */
    private function syncStatusesFromMeta($templates): void
    {
        $templates = collect($templates)->filter()->filter(fn($t) => filled($t->meta_name));
        if ($templates->isEmpty()) {
            return;
        }

        try {
            $remote = collect($this->whatsapp->listMessageTemplates())->keyBy('name');
        } catch (\Throwable $e) {
            return; // Meta unreachable — keep what we have.
        }

        foreach ($templates as $template) {
            $meta = $remote->get($template->meta_name);
            if (!$meta) {
                continue;
            }

            $status = $this->mapMetaStatus($meta['status'] ?? null);
            $dirty = false;

            if ($template->status !== $status) {
                $template->status = $status;
                if ($status === WhatsappTemplate::STATUS_APPROVED && is_null($template->approved_at)) {
                    $template->approved_at = now();
                }
                if ($status !== WhatsappTemplate::STATUS_REJECTED) {
                    $template->rejected_reason = null;
                }
                $dirty = true;
            }

            if ($dirty) {
                $template->save();
            }
        }
    }

    private function mapMetaStatus(?string $status): string
    {
        return match (strtoupper((string) $status)) {
            'APPROVED' => WhatsappTemplate::STATUS_APPROVED,
            'REJECTED' => WhatsappTemplate::STATUS_REJECTED,
            'PAUSED' => WhatsappTemplate::STATUS_PAUSED,
            'DISABLED' => WhatsappTemplate::STATUS_DISABLED,
            default => WhatsappTemplate::STATUS_PENDING,
        };
    }
}
