<?php

namespace App\Http\Controllers\Admin;

use App\Helpers\ApiResponse;
use App\Helpers\CacheHelper;
use App\Helpers\TranslationHelper;
use App\Http\Controllers\Controller;
use App\Models\AdditionalActivity;
use App\Models\AdditionalActivityTranslation;
use App\Models\Form;
use App\Models\FormTranslation;
use App\Models\FormNotification;
use App\Models\Page;
use App\Models\PageTranslationSubmission;
use App\Models\Program;
use App\Models\ProgramTranslation;
use App\Models\Testimonial;
use App\Models\TestimonialTranslation;
use App\Models\WhatsappMessage;
use App\Models\WhatsappMessageTranslation;
use App\Services\FormContentNormalizerService;
use App\Services\FormNotificationTranslationSyncService;
use App\Services\FormTranslationSyncService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Symfony\Component\HttpFoundation\Response;

class TranslateController extends Controller
{
    public function __construct(
        private readonly FormTranslationSyncService $formTranslationSyncService,
        private readonly FormNotificationTranslationSyncService $formNotificationTranslationSyncService,
        private readonly FormContentNormalizerService $formContentNormalizerService
    ) {
    }

    public function translate(Request $request, TranslationHelper $translator)
    {
        $validator = Validator::make($request->all(), [
            'language' => 'required|string|max:100',
            'method' => 'required',
        ]);

        if ($validator->fails()) {
            return ApiResponse::error(
                $validator->errors()->first(),
                Response::HTTP_UNPROCESSABLE_ENTITY
            );
        }

        try {
            $user = Auth::user();
            $isAuthorized = in_array($user->role, ['super_admin', 'franchise_admin', 'franchise_editor']);

            if (!$isAuthorized) {
                return ApiResponse::error('Unauthorized.', Response::HTTP_FORBIDDEN);
            }

            if ($request->page_id) {
                return $this->translatePage($request, $translator, $user);
            }

            $type = $request->type;

            return match ($type) {
                'testimonials' => $this->handleEntityTranslation($request, $translator, $user, 'testimonials'),
                'activities' => $this->handleEntityTranslation($request, $translator, $user, 'activities'),
                'programs' => $this->handleEntityTranslation($request, $translator, $user, 'programs'),
                'forms' => $this->handleEntityTranslation($request, $translator, $user, 'forms'),
                'whatsapp_messages' => $this->handleWhatsappMessagesTranslation($request, $translator, $user),
                default => ApiResponse::error('Invalid translation type.', Response::HTTP_BAD_REQUEST),
            };
        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    private function translatePage(Request $request, TranslationHelper $translator, $user)
    {
        $translation = PageTranslationSubmission::where('page_id', $request->page_id)
            ->where('franchisee_id', $user->franchisee_id)
            ->where('language_code', 'en')
            ->first();

        $page = Page::query()->findOrFail($request->page_id);

        $original = $translation->translated_content
            ?? $page->content;

        if (empty($original)) {
            Log::warning('Translation failed: No content found for page.', [
                'page_id' => $request->page_id,
                'franchisee_id' => $user->franchisee_id
            ]);
            return ApiResponse::error('No content found to translate for this page.');
        }

        $seoTitleOriginal = $translation?->seo_title ?? $page->seo_title;
        $seoDescriptionOriginal = $translation?->seo_description ?? $page->seo_description;

        $translatedJson = $translator->translate($original, $request->language);

        // Translate SEO strings (keeps editor behavior in sync with content translation)
        $translatedSeo = $translator->translate([
            'seo_title' => $seoTitleOriginal,
            'seo_description' => $seoDescriptionOriginal,
        ], $request->language);

        if (empty($translatedJson)) {
            Log::error('Translation failed: Translator returned empty result.', [
                'page_id' => $request->page_id,
                'language' => $request->language
            ]);
            return ApiResponse::error('Translation service returned no content. Please try again.');
        }

        return ApiResponse::success([
            'content' => $translatedJson,
            'seo_title' => $translatedSeo['seo_title'] ?? $seoTitleOriginal,
            'seo_description' => $translatedSeo['seo_description'] ?? $seoDescriptionOriginal,
            'lang' => $request->language,
        ], 'Translation successful');
    }

    private function handleEntityTranslation(Request $request, TranslationHelper $translator, $user, string $type)
    {
        if ($type === 'forms') {
            return $this->handleFormsTranslation($request, $translator, $user);
        }

        if ($type === 'testimonials') {
            return $this->handleTestimonialsTranslation($request, $translator, $user);
        }
        $method = $request->input('method');
        $language = $request->language;
        $languageCode = $request->input('language-code');

        $ids = $this->getIdsFromRequest($request, $type);

        $isGlobal = ($user->role === 'super_admin');
        $translationExit = [];
        $translationDone = [];

        if (!empty($ids) && is_array($ids)) {
            foreach ($ids as $id) {
                $original = $this->findModelByType($type, $id);

                if (!$original) {
                    continue;
                }

                if (!$this->isEnglishSource($original, $type, $user->franchisee_id)) {
                    $translationExit[] = 'Only English content can be used as source for translation.';
                    continue;
                }

                $parentId = $this->getParentId($original, $type);

                $existingTranslation = $this->findExistingTranslation($type, $original, $user->franchisee_id, $parentId, $languageCode);
                if ($existingTranslation) {
                    if ($method === 'openAI') {
                        $translatedSource = $this->applyTranslatedFields(clone $original, $type, $translator, $language, $user->franchisee_id);
                        $existingTranslation->fill($this->buildTranslatedUpdateData($translatedSource, $type));
                        $existingTranslation->save();
                        $translationDone[] = $existingTranslation->fresh();
                    } else {
                        $translationExit[] = $this->getAlreadyExistsMessage($type, $language);
                    }
                    continue;
                }

                if (
                    !in_array($type, ['programs', 'activities'], true) &&
                    $user->role !== 'super_admin' &&
                    !$this->englishTranslationExists($type, $user->franchisee_id, $parentId) &&
                    $language !== 'en'
                ) {
                    $this->makeDuplicate($original, 'en', $user, false, $type);
                }

                if ($method === 'openAI') {
                    $original = $this->applyTranslatedFields($original, $type, $translator, $language, $user->franchisee_id);
                }

                $translationDone[] = $this->makeDuplicate($original, $languageCode, $user, $isGlobal, $type);
            }
        }

        CacheHelper::forgetByTag($this->getCacheTag($type));

        return ApiResponse::success(
            [
                'translation_exit' => $translationExit,
                'translation_done' => $translationDone,
            ],
            $this->getResultMessage($type, count($translationDone), count($translationExit), $translationExit)
        );
    }

    private function getIdsFromRequest(Request $request, string $type): array
    {
        return match ($type) {
            'activities' => $request->input('activity_ids', []),
            'programs' => $request->input('program_ids', []),
            default => [],
        };
    }

    private function findModelByType(string $type, $id)
    {
        return match ($type) {
            'activities' => AdditionalActivity::find($id) ?? AdditionalActivityTranslation::findOrFail($id),
            'programs' => Program::findOrFail($id),
            default => null,
        };
    }

    private function getParentId($original, string $type)
    {
        return match ($type) {
            'activities' => $original instanceof AdditionalActivityTranslation
                ? ($original->additionalActivity?->parent_activity_id ?? $original->additional_activity_id)
                : ($original->parent_activity_id ?? $original->id),
            'programs' => $original->parent_program_id ?? $original->id,
            default => $original->id,
        };
    }

    private function translationExists(string $type, $original, $franchiseeId, $parentId, string $languageCode): bool
    {
        return (bool) $this->findExistingTranslation($type, $original, $franchiseeId, $parentId, $languageCode);
    }

    private function findExistingTranslation(string $type, $original, $franchiseeId, $parentId, string $languageCode)
    {
        return match ($type) {
            'activities' => AdditionalActivityTranslation::where('franchisee_id', $franchiseeId)
                ->whereIn('additional_activity_id', AdditionalActivity::where('franchisee_id', $franchiseeId)
                    ->where(function ($q) use ($parentId) {
                        $q->where('parent_activity_id', $parentId)
                            ->orWhere('id', $parentId);
                    })->pluck('id'))
                ->where('language', $languageCode)
                ->whereNull('deleted_at')
                ->first(),
            'programs' => ProgramTranslation::where('franchisee_id', $franchiseeId)
                ->whereIn('program_id', Program::where('franchisee_id', $franchiseeId)
                    ->where(function ($q) use ($parentId) {
                        $q->where('parent_program_id', $parentId)
                            ->orWhere('id', $parentId);
                    })->pluck('id'))
                ->where('language', $languageCode)
                ->whereNull('deleted_at')
                ->first(),
            default => null,
        };
    }

    private function englishTranslationExists(string $type, $franchiseeId, $parentId): bool
    {
        return match ($type) {
            'activities' => AdditionalActivityTranslation::where('franchisee_id', $franchiseeId)
                ->whereIn('additional_activity_id', AdditionalActivity::where('franchisee_id', $franchiseeId)
                    ->where(function ($q) use ($parentId) {
                        $q->where('parent_activity_id', $parentId)
                            ->orWhere('id', $parentId);
                    })->pluck('id'))
                ->where('language', 'en')
                ->whereNull('deleted_at')
                ->exists(),

            'programs' => ProgramTranslation::where('franchisee_id', $franchiseeId)
                ->whereIn('program_id', Program::where('franchisee_id', $franchiseeId)
                    ->where(function ($q) use ($parentId) {
                        $q->where('parent_program_id', $parentId)
                            ->orWhere('id', $parentId);
                    })->pluck('id'))
                ->where('language', 'en')
                ->whereNull('deleted_at')
                ->exists(),

            default => false,
        };
    }

    private function applyTranslatedFields($original, string $type, TranslationHelper $translator, string $language, ?string $franchiseeId = null)
    {
        $fields = $this->getTranslatableFields($original, $type, $franchiseeId);

        if (empty($fields)) {
            return $original;
        }

        $translated = $translator->translate($fields, $language);

        foreach (array_keys($fields) as $field) {
            $nextValue = $translated[$field] ?? $original->{$field};
            if ($type === 'programs' && $field === 'program_details') {
                $nextValue = $this->normalizeProgramDetails($nextValue, $original->program_details ?? []);
            }

            $original->{$field} = $nextValue;
        }

        return $original;
    }

    private function getTranslatableFields($original, string $type, ?string $franchiseeId = null): array
    {
        return match ($type) {
            'activities' => (function () use ($original) {
                $source = $this->resolveActivityTranslationSource($original, 'en');

                return [
                    'title' => $source?->title ?? '',
                    'seo_title' => $source?->seo_title ?? '',
                    'seo_description' => $source?->seo_description ?? '',
                    'activity_details' => $source?->activity_details ?? '',
                ];
            })(),

            'programs' => (function () use ($original, $franchiseeId) {
                $source = $original instanceof ProgramTranslation
                    ? $original
                    : ($original instanceof Program
                        ? $this->resolvePublishedGlobalEnglishSource($original)
                        : null);

                if (!$source) {
                    return [];
                }

                return [
                    'title' => $source->title ?? '',
                    'seo_title' => $source->seo_title ?? '',
                    'seo_description' => $source->seo_description ?? '',
                    'sub_heading' => $source->sub_heading ?? '',
                    'no_of_lessons' => $source->no_of_lessons ?? '',
                    'duration' => $source->duration ?? '',
                    'age_range' => $source->age_range ?? '',
                    'button_text' => $source->button_text ?? '',
                    'description' => $source->description ?? '',
                    'age_text' => $source->age_text ?? '',
                    'duration_text' => $source->duration_text ?? '',
                    'lesson_duration_text' => $source->lesson_duration_text ?? '',
                    'tag' => $source->tag ?? '',
                    'program_details' => $source->program_details ?? '',
                ];
            })(),

            default => [],
        };
    }

    private function getAlreadyExistsMessage(string $type, string $language): string
    {
        return match ($type) {
            'activities' => "This activities translation already exists in {$language} for your franchise.",
            'programs' => "This program translation already exists in {$language} for your franchise.",
            default => "This translation already exists in {$language} for your franchise.",
        };
    }

    private function getSuccessMessage(string $type): string
    {
        return match ($type) {
            'activities' => 'Activities translation successfully',
            'programs' => 'Programs translation successfully',
            'whatsapp_messages' => 'WhatsApp messages translation successfully',
            default => 'Translation successfully',
        };
    }

    private function getResultMessage(string $type, int $doneCount, int $existsCount, array $exitMessages = []): string
    {
        if ($doneCount > 0 && $existsCount === 0) {
            return $this->getSuccessMessage($type);
        }

        if ($doneCount === 0 && $existsCount > 0) {
            if (collect($exitMessages)->contains(fn($message) => str_contains($message, 'Only English'))) {
                return 'Only English content can be used as source for translation.';
            }

            return 'Translation already exists for selected item(s).';
        }

        if ($doneCount > 0 && $existsCount > 0) {
            return 'Translation completed for new items. Existing translations were skipped.';
        }

        return 'No items were translated.';
    }

    private function isEnglishSource($original, ?string $type = null, ?string $franchiseeId = null): bool
    {
        if ($type === 'programs' && $original instanceof Program) {
            $source = $this->resolvePublishedGlobalEnglishSource($original);

            return !is_null($source);
        }

        if ($type === 'activities') {
            if ($original instanceof AdditionalActivityTranslation) {
                return strtolower((string) ($original->language ?? 'en')) === 'en';
            }

            if ($original instanceof AdditionalActivity) {
                $globalActivityId = $original->is_global ? $original->id : ($original->parent_activity_id ?: $original->id);

                return AdditionalActivityTranslation::where('additional_activity_id', $globalActivityId)
                    ->whereNull('franchisee_id')
                    ->where('language', 'en')
                    ->whereIn('status', ['publish', 'published', 'active'])
                    ->exists();
            }
        }

        return strtolower((string) ($original->language ?? 'en')) === 'en';
    }

    private function getCacheTag(string $type): string
    {
        return match ($type) {
            'testimonials' => 'testimonials',
            'activities' => 'additional_activities',
            'programs' => 'programs',
            default => '',
        };
    }

    /**
     * Helper to check if string is valid JSON.
     */
    private function isJson(string $string): bool
    {
        json_decode($string);
        return json_last_error() === JSON_ERROR_NONE;
    }

    private function makeDuplicate($original, string $language, $auth, bool $isGlobal, string $type)
    {
        $language = strtolower(trim($language));

        if ($type === 'programs') {
            if (!$original instanceof Program) {
                throw new \InvalidArgumentException('Invalid program source for translation.');
            }

            $targetProgram = $this->resolveTargetProgram($original, $auth, $isGlobal);
            $source = $this->resolvePublishedGlobalEnglishSource($original);
            $fallbackTitle = trim((string) ($original->title ?? $source?->title ?? 'Program'));
            $programData = [
                'title' => $fallbackTitle !== '' ? $fallbackTitle : 'Program',
                'seo_title' => $original->seo_title ?? $source?->seo_title,
                'seo_description' => $original->seo_description ?? $source?->seo_description,
                'sub_heading' => $original->sub_heading ?? $source?->sub_heading,
                'button_text' => $original->button_text ?? $source?->button_text,
                'age_range' => $original->age_range ?? $source?->age_range,
                'duration' => $original->duration ?? $source?->duration,
                'no_of_lessons' => $original->no_of_lessons ?? $source?->no_of_lessons,
                'description' => $original->description ?? $source?->description,
                'age_text' => $original->age_text ?? $source?->age_text,
                'duration_text' => $original->duration_text ?? $source?->duration_text,
                'lesson_duration_text' => $original->lesson_duration_text ?? $source?->lesson_duration_text,
                'tag' => $original->tag ?? $source?->tag,
                'program_details' => $this->normalizeProgramDetails($original->program_details ?? null, $source?->program_details ?? []),
                'status' => 'draft',
            ];

            return ProgramTranslation::updateOrCreate([
                'program_id' => $targetProgram->id,
                'franchisee_id' => $isGlobal ? null : $auth->franchisee_id,
                'language' => $language,
            ], $programData);
        }

        if ($type === 'activities') {
            $source = $this->resolveActivityTranslationSource($original, $language);
            $base = $original instanceof AdditionalActivityTranslation
                ? $original->additionalActivity
                : ($original instanceof AdditionalActivity ? $original : null);

            if (!$base instanceof AdditionalActivity) {
                throw new \InvalidArgumentException('Invalid activity source for translation.');
            }

            if (!$isGlobal && $base->franchisee_id !== $auth->franchisee_id) {
                $base = AdditionalActivity::firstOrCreate([
                    'franchisee_id' => $auth->franchisee_id,
                    'parent_activity_id' => $base->id,
                ], [
                    'slug' => $base->slug,
                    'cw_program_id' => $base->cw_program_id,
                    'is_global' => false,
                    'is_enabled' => $base->is_enabled,
                    'order_no' => $base->order_no,
                    'is_required_for_translation' => $base->is_required_for_translation,
                ]);
            }

            return AdditionalActivityTranslation::updateOrCreate([
                'additional_activity_id' => $base->id,
                'franchisee_id' => $isGlobal ? null : $auth->franchisee_id,
                'language' => $language,
            ], [
                'title' => $source?->title ?? 'Activity',
                'seo_title' => $source?->seo_title,
                'seo_description' => $source?->seo_description,
                'activity_details' => $source?->activity_details ?? null,
                'status' => 'draft',
            ]);
        }

        throw new \InvalidArgumentException("Unsupported duplicate type: {$type}");
    }

    private function buildTranslatedUpdateData($source, string $type): array
    {
        return match ($type) {
            'activities' => [
                'title' => $source->title ?? null,
                'seo_title' => $source->seo_title ?? null,
                'seo_description' => $source->seo_description ?? null,
                'activity_details' => $source->activity_details ?? null,
            ],
            'programs' => [
                'title' => $source->title ?? null,
                'seo_title' => $source->seo_title ?? null,
                'seo_description' => $source->seo_description ?? null,
                'sub_heading' => $source->sub_heading ?? null,
                'no_of_lessons' => $source->no_of_lessons ?? null,
                'duration' => $source->duration ?? null,
                'age_range' => $source->age_range ?? null,
                'button_text' => $source->button_text ?? null,
                'description' => $source->description ?? null,
                'age_text' => $source->age_text ?? null,
                'duration_text' => $source->duration_text ?? null,
                'lesson_duration_text' => $source->lesson_duration_text ?? null,
                'tag' => $source->tag ?? null,
                'program_details' => $this->normalizeProgramDetails($source->program_details ?? null, []),
            ],
            default => [],
        };
    }

    private function resolveActivityTranslationSource($original, string $language = 'en'): ?AdditionalActivityTranslation
    {
        if ($original instanceof AdditionalActivityTranslation) {
            return $original;
        }

        if (!$original instanceof AdditionalActivity) {
            return null;
        }

        $globalActivityId = $original->is_global ? $original->id : ($original->parent_activity_id ?: $original->id);

        $translation = AdditionalActivityTranslation::where('additional_activity_id', $globalActivityId)
            ->whereNull('franchisee_id')
            ->where('language', strtolower($language))
            ->whereIn('status', ['publish', 'published', 'active'])
            ->first();

        if ($translation) {
            return $translation;
        }

        return AdditionalActivityTranslation::where('additional_activity_id', $globalActivityId)
            ->whereNull('franchisee_id')
            ->where('language', 'en')
            ->whereIn('status', ['publish', 'published', 'active'])
            ->first();
    }

    private function resolveTargetProgram(Program $original, $auth, bool $isGlobal): Program
    {
        if ($isGlobal) {
            return $original;
        }

        if ($original->franchisee_id === $auth->franchisee_id) {
            return $original;
        }

        $existing = Program::where('franchisee_id', $auth->franchisee_id)
            ->where(function ($query) use ($original) {
                $query->where('parent_program_id', $original->id)
                    ->orWhere('id', $original->id);
            })
            ->first();

        if ($existing) {
            return $existing;
        }

        return Program::create([
            'franchisee_id' => $auth->franchisee_id,
            'parent_program_id' => $original->id,
            'cw_program_id' => $original->cw_program_id,
            'slug' => $original->slug,
            'header_image' => $original->header_image,
            'program_icon' => $original->program_icon,
            'color' => $original->color,
            'background_color' => $original->background_color,
            'is_enabled' => $original->is_enabled,
            'is_global' => false,
            'order_no' => $original->order_no,
            'is_required_for_translation' => $original->is_required_for_translation,
        ]);
    }

    private function resolvePublishedGlobalEnglishSource(Program $program): ?ProgramTranslation
    {
        $globalProgramId = $program->is_global ? $program->id : ($program->parent_program_id ?: $program->id);

        return ProgramTranslation::where('program_id', $globalProgramId)
            ->whereNull('franchisee_id')
            ->where('language', 'en')
            ->whereIn('status', ['publish', 'published', 'active'])
            ->first();
    }


    /**
     * Franchisee: AI-translate WhatsApp flow message(s) into a language and upsert them.
     * Uses the same /admin/translate entry point as programs/activities/testimonials —
     * dispatched by type, ids passed in `whatsapp_message_ids`.
     */
    private function handleWhatsappMessagesTranslation(Request $request, TranslationHelper $translator, $user)
    {
        if ($user->role === 'super_admin') {
            return ApiResponse::error('Translations are for franchisees.', Response::HTTP_BAD_REQUEST);
        }

        $languageCode = strtolower((string) ($request->input('language-code') ?: $request->input('language')));
        if ($languageCode === '' || $languageCode === 'en') {
            return ApiResponse::error('Choose a language to translate into.', Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        $ids = $request->input('whatsapp_message_ids', []);
        $translationExit = [];
        $translationDone = [];

        foreach ((array) $ids as $id) {
            $message = WhatsappMessage::find($id);
            if (!$message) {
                continue;
            }

            $fields = array_filter([
                'header_text' => $message->header_text,
                'body_text' => $message->body_text,
                'footer_text' => $message->footer_text,
            ], fn($v) => filled($v));

            $translated = !empty($fields) ? $translator->translate($fields, $request->language) : [];

            $translationDone[] = WhatsappMessageTranslation::updateOrCreate(
                [
                    'whatsapp_message_id' => $message->id,
                    'franchisee_id' => $user->franchisee_id,
                    'language_code' => $languageCode,
                ],
                [
                    'header_text' => $translated['header_text'] ?? $message->header_text,
                    'body_text' => $translated['body_text'] ?? $message->body_text,
                    'footer_text' => $translated['footer_text'] ?? $message->footer_text,
                ]
            );
        }

        return ApiResponse::success([
            'translation_exit' => $translationExit,
            'translation_done' => $translationDone,
        ], $this->getResultMessage('whatsapp_messages', count($translationDone), count($translationExit), $translationExit));
    }

    private function handleTestimonialsTranslation(Request $request, TranslationHelper $translator, $user)
    {
        $method = $request->input('method');
        $language = strtolower((string) ($request->input('language-code') ?: $request->input('language')));
        $ids = $request->input('testimonial_ids', []);

        $translationExit = [];
        $translationDone = [];

        foreach ($ids as $id) {
            $base = Testimonial::withTrashed()->with('translations')->find($id);
            if (!$base) {
                continue;
            }

            $targetBase = $this->resolveTargetTestimonialBase($base, $user);
            $source = $this->resolveTestimonialSourceTranslation($targetBase, 'en');
            if (!$source) {
                $translationExit[] = 'Only English content can be used as source for translation.';
                continue;
            }

            $target = TestimonialTranslation::firstOrNew([
                'testimonial_id' => $targetBase->id,
                'language' => $language,
            ]);

            if (!$target->exists || $method === 'manual') {
                $target->fill([
                    'parent_name' => $source->parent_name,
                    'role' => $source->role,
                    'comment' => $source->comment,
                    'status' => 'draft',
                ]);
                if (!$target->exists) {
                    $target->version = 1;
                }
                $target->save();
            }

            if ($method === 'openAI') {
                $payload = [
                    'parent_name' => $translator->translate(['value' => (string) ($source->parent_name ?? '')], $request->language)['value'] ?? $source->parent_name,
                    'role' => $translator->translate(['value' => (string) ($source->role ?? '')], $request->language)['value'] ?? $source->role,
                    'comment' => $translator->translate(['value' => (string) ($source->comment ?? '')], $request->language)['value'] ?? $source->comment,
                ];

                $target->fill([
                    'parent_name' => $payload['parent_name'],
                    'role' => $payload['role'],
                    'comment' => $payload['comment'],
                    'status' => $target->status ?: 'draft',
                ]);
                if (!$target->exists) {
                    $target->version = 1;
                }
                $target->save();
            }

            $translationDone[] = $this->buildTestimonialTranslationFamilyResponse($targetBase->fresh('translations'), $user);
        }

        CacheHelper::forgetByTag('testimonials');

        return ApiResponse::success([
            'translation_exit' => $translationExit,
            'translation_done' => $translationDone,
        ], $this->getResultMessage('testimonials', count($translationDone), count($translationExit), $translationExit));
    }

    private function resolveTargetTestimonialBase(Testimonial $base, $user): Testimonial
    {
        if ($user->role === 'super_admin') {
            return $base;
        }

        if ($base->franchisee_id === $user->franchisee_id) {
            return $base;
        }

        return Testimonial::firstOrCreate([
            'franchisee_id' => $user->franchisee_id,
            'parent_testimonials_id' => $base->id,
        ], [
            'is_global' => false,
            'order_no' => $base->order_no,
            'is_required_for_translation' => $base->is_required_for_translation,
        ]);
    }

    private function resolveTestimonialSourceTranslation(Testimonial $base, string $language = 'en'): ?TestimonialTranslation
    {
        $globalBaseId = $base->is_global ? $base->id : ($base->parent_testimonials_id ?: $base->id);

        $translation = TestimonialTranslation::where('testimonial_id', $globalBaseId)
            ->where('language', strtolower($language))
            ->where('status', 'publish')
            ->first();

        if ($translation) {
            return $translation;
        }

        return TestimonialTranslation::where('testimonial_id', $globalBaseId)
            ->where('language', 'en')
            ->where('status', 'publish')
            ->first();
    }

    private function buildTestimonialTranslationFamilyResponse(Testimonial $base, $user): array
    {
        $globalBaseId = $base->is_global ? $base->id : ($base->parent_testimonials_id ?: $base->id);
        $ids = array_values(array_unique([$base->id, $globalBaseId]));

        $translations = TestimonialTranslation::whereIn('testimonial_id', $ids)
            ->whereNull('deleted_at')
            ->get();

        $availableLanguages = $translations->pluck('language')
            ->map(fn($code) => strtolower((string) $code))
            ->unique()
            ->sort()
            ->values()
            ->all();

        $family = collect($availableLanguages)->map(function (string $lang) use ($base) {
            $translation = TestimonialTranslation::where('testimonial_id', $base->id)->where('language', $lang)->first()
                ?? TestimonialTranslation::where('testimonial_id', $base->is_global ? $base->id : ($base->parent_testimonials_id ?: $base->id))->where('language', $lang)->where('status', 'publish')->first()
                ?? TestimonialTranslation::where('testimonial_id', $base->is_global ? $base->id : ($base->parent_testimonials_id ?: $base->id))->where('language', 'en')->where('status', 'publish')->first();

            return [
                'translation_id' => $translation?->id,
                'language' => $lang,
                'parent_name' => $translation?->parent_name,
                'role' => $translation?->role,
                'comment' => $translation?->comment,
                'status' => $translation?->status ?? 'draft',
            ];
        })->values()->all();

        return [
            'id' => $base->id,
            'available_languages' => $availableLanguages,
            'translation_family' => $family,
        ];
    }

    private function handleFormsTranslation(Request $request, TranslationHelper $translator, $user)
    {
        $method = $request->input('method');
        $language = strtolower((string) ($request->input('language-code') ?: $request->input('language')));
        $ids = $request->input('form_ids', []);

        $translationExit = [];
        $translationDone = [];

        foreach ($ids as $id) {
            $form = Form::withTrashed()->with(['translations', 'notifications.translations', 'parentForm.translations', 'parentForm.notifications.translations'])->find($id);
            if (!$form) {
                continue;
            }

            $targetForm = $this->resolveTargetFormForFormsTranslation($form, $user);
            $sourceTranslation = $this->resolveSourceFormTranslation($targetForm, 'en');
            if (!$sourceTranslation) {
                $translationExit[] = 'Only English content can be used as source for translation.';
                continue;
            }

            $basePayload = [
                'name' => $sourceTranslation->name,
                'description' => $sourceTranslation->description,
                'fields' => $sourceTranslation->fields,
                'pages' => $sourceTranslation->pages,
                'form_setting' => $sourceTranslation->form_setting,
                'status' => 'Draft',
                'translated' => $method === 'openAI',
            ];
            $targetTranslation = $user->role === 'super_admin'
                ? $this->formTranslationSyncService->saveGlobalTranslation($targetForm, $language, $basePayload)
                : $this->formTranslationSyncService->saveFranchiseManualTranslation($targetForm, $language, $basePayload);

            if ($method === 'openAI') {
                $shouldTranslateBasicInfo = $user->role === 'super_admin';
                $payload = $this->formContentNormalizerService->normalizeTranslationPayload([
                    'name' => $shouldTranslateBasicInfo
                        ? ($translator->translate(['value' => $sourceTranslation->name ?? ''], $request->language)['value'] ?? $sourceTranslation->name)
                        : $sourceTranslation->name,
                    'description' => $shouldTranslateBasicInfo
                        ? ($translator->translate(['value' => $sourceTranslation->description ?? ''], $request->language)['value'] ?? $sourceTranslation->description)
                        : $sourceTranslation->description,
                    'fields' => $this->translateFormStructure($sourceTranslation->fields, $translator, $request->language),
                    'pages' => $sourceTranslation->pages,
                    'form_setting' => $this->translateFormStructure($sourceTranslation->form_setting, $translator, $request->language),
                ]);

                $translatedPayload = [
                    'name' => $payload['name'] ?? null,
                    'description' => $payload['description'] ?? null,
                    'fields' => $payload['fields'] ?? null,
                    'pages' => $payload['pages'] ?? null,
                    'form_setting' => $payload['form_setting'] ?? null,
                    'status' => 'Draft',
                    'translated' => true,
                ];
                $targetTranslation = $user->role === 'super_admin'
                    ? $this->formTranslationSyncService->saveGlobalTranslation($targetForm, $language, $translatedPayload)
                    : $this->formTranslationSyncService->saveFranchiseManualTranslation($targetForm, $language, $translatedPayload);
            }

            $this->syncFormNotificationTranslations($targetForm, $sourceTranslation->form_id, $language, $method, $translator, $request->language);

            $translationDone[] = $this->buildFormTranslationFamilyResponse($targetForm->fresh(['translations', 'notifications.translations', 'parentForm.translations', 'parentForm.notifications.translations']));
        }

        CacheHelper::forgetByTag('forms');

        return ApiResponse::success([
            'translation_exit' => $translationExit,
            'translation_done' => $translationDone,
        ], $this->getResultMessage('forms', count($translationDone), count($translationExit), $translationExit));
    }

    private function resolveTargetFormForFormsTranslation(Form $form, $user): Form
    {
        if ($user->role === 'super_admin') {
            return $form;
        }

        if ($form->franchisee_id === $user->franchisee_id) {
            return $form;
        }

        $target = Form::firstOrCreate([
            'franchisee_id' => $user->franchisee_id,
            'parent_form_id' => $form->id,
        ], [
            'is_global' => false,
            'form_setting' => $form->form_setting,
            'is_required_for_translation' => $form->is_required_for_translation,
            'order_no' => $form->order_no,
        ]);

        $globalNotifications = FormNotification::where('form_id', $form->id)->get();
        foreach ($globalNotifications as $globalNotification) {
            FormNotification::updateOrCreate([
                'form_id' => $target->id,
                'source_global_notification_id' => $globalNotification->id,
            ], [
                'notification_name' => $globalNotification->notification_name,
                'to_email' => $globalNotification->to_email,
                'from_name' => $globalNotification->from_name,
                'from_email' => $globalNotification->from_email,
                'cc' => $globalNotification->cc,
                'bcc' => $globalNotification->bcc,
                'event_key' => $globalNotification->event_key,
            ]);
        }

        return $target;
    }

    private function resolveSourceFormTranslation(Form $form, string $language = 'en'): ?FormTranslation
    {
        $source = FormTranslation::where('form_id', $form->id)->where('language', $language)->first();
        if ($source) {
            return $source;
        }

        $globalId = $form->is_global ? $form->id : ($form->parent_form_id ?: $form->id);

        return FormTranslation::where('form_id', $globalId)->where('language', $language)->first();
    }

    private function syncFormNotificationTranslations(Form $targetForm, string $sourceFormId, string $language, string $method, TranslationHelper $translator, string $targetLanguage): void
    {
        $sourceNotifications = FormNotification::where('form_id', $sourceFormId)->with('translations')->get()->keyBy('event_key');
        $targetNotifications = FormNotification::where('form_id', $targetForm->id)->with('translations')->get()->keyBy('event_key');

        foreach ($sourceNotifications as $eventKey => $sourceNotification) {
            $targetNotification = $targetNotifications->get($eventKey);
            if (!$targetNotification) {
                $targetNotification = FormNotification::updateOrCreate([
                    'form_id' => $targetForm->id,
                    'source_global_notification_id' => $sourceNotification->id,
                ], [
                    'notification_name' => $sourceNotification->notification_name,
                    'to_email' => $sourceNotification->to_email,
                    'from_name' => $sourceNotification->from_name,
                    'from_email' => $sourceNotification->from_email,
                    'cc' => $sourceNotification->cc,
                    'bcc' => $sourceNotification->bcc,
                    'event_key' => $sourceNotification->event_key,
                ]);
            } else {
                $targetNotification->update([
                    'notification_name' => $sourceNotification->notification_name,
                    'to_email' => $sourceNotification->to_email,
                    'from_name' => $sourceNotification->from_name,
                    'from_email' => $sourceNotification->from_email,
                    'cc' => $sourceNotification->cc,
                    'bcc' => $sourceNotification->bcc,
                    'event_key' => $sourceNotification->event_key,
                    'source_global_notification_id' => $sourceNotification->id,
                ]);
            }

            $sourceTranslation = $sourceNotification->translations->firstWhere('language', 'en')
                ?: $sourceNotification->translations->first();

            if (!$sourceTranslation) {
                continue;
            }

            $translatedPayload = [];
            if ($method === 'openAI') {
                $translated = $translator->translate([
                    'subject' => $sourceTranslation->subject ?? '',
                    'message' => $sourceTranslation->message ?? '',
                ], $targetLanguage);

                $translatedPayload['subject'] = $translated['subject'] ?? $sourceTranslation->subject;
                $translatedPayload['message'] = $translated['message'] ?? $sourceTranslation->message;
            } else {
                $translatedPayload['subject'] = $sourceTranslation->subject;
                $translatedPayload['message'] = $sourceTranslation->message;
            }

            $translatedPayload['status'] = $sourceTranslation->status ?? 'Draft';

            if ($targetForm->is_global) {
                $this->formNotificationTranslationSyncService->saveGlobalTranslation($targetNotification, $language, $translatedPayload);
            } else {
                $this->formNotificationTranslationSyncService->saveFranchiseManualTranslation($targetNotification, $language, $translatedPayload);
            }
        }
    }

    private function translateFormStructure($value, TranslationHelper $translator, string $language, array $path = [])
    {
        if (is_string($value)) {
            $key = strtolower((string) (end($path) ?: ''));
            $skipValueKeys = [
                'id', 'field_id', 'validation', 'validation_key', 'validation_keys', 'event_key',
                'type', 'name', 'key', 'slug', 'email', 'to_email', 'from_email', 'cc', 'bcc',
            ];

            if (in_array($key, $skipValueKeys, true)) {
                return $value;
            }

            $translated = $translator->translate(['value' => $value], $language);
            return $translated['value'] ?? $value;
        }

        if (is_array($value)) {
            $isAssoc = array_keys($value) !== range(0, count($value) - 1);
            $translated = [];
            foreach ($value as $k => $v) {
                $translated[$k] = $this->translateFormStructure($v, $translator, $language, array_merge($path, [(string) $k]));
            }
            return $isAssoc ? $translated : array_values($translated);
        }

        return $value;
    }

    private function buildFormTranslationFamilyResponse(Form $form): array
    {
        $form->loadMissing(['translations', 'notifications.translations', 'parentForm.translations', 'parentForm.notifications.translations']);

        $languages = collect($form->translations)->pluck('language');
        if ($form->parentForm) {
            $languages = $languages->merge(collect($form->parentForm->translations)->pluck('language'));
        }

        $available = $languages->filter()->unique()->sort()->values()->all();

        return [
            'id' => $form->id,
            'parent_form_id' => $form->parent_form_id,
            'available_languages' => $available,
            'translation_family' => collect($available)->map(function ($lang) use ($form) {
                $local = $form->translations->firstWhere('language', $lang);
                $global = $form->parentForm?->translations?->firstWhere('language', $lang)
                    ?: $form->parentForm?->translations?->firstWhere('language', 'en');
                $display = $local ?: $global;

                return [
                    'language' => $lang,
                    'translation_id' => $display?->id,
                    'name' => $display?->name,
                    'description' => $display?->description,
                    'fields' => $display?->fields,
                    'pages' => $display?->pages,
                    'form_setting' => $display?->form_setting,
                    'status' => $display?->status,
                ];
            })->values()->all(),
        ];
    }

    private function normalizeProgramDetails($value, array $fallback = []): array
    {
        if (is_array($value)) {
            return $value;
        }

        if (is_string($value) && $this->isJson($value)) {
            $decoded = json_decode($value, true);
            if (is_array($decoded)) {
                return $decoded;
            }
        }

        return is_array($fallback) ? $fallback : [];
    }
}
