<?php
namespace App\Http\Controllers\Api\V1;

use App\Helpers\ApiResponse;
use App\Helpers\ZohoHelper;
use App\Http\Controllers\Api\BaseApiController;
use App\Models\Form;
use App\Models\FormSubmission;
use App\Models\Franchisee;
use App\Models\Page;
use App\Models\PolicyConsent;
use App\Services\ClasswiseRegistrationService;
use App\Services\FormSubmissionNotificationService;
use App\Services\RegistrationPricingHelper;
use App\Services\TranslateTemplatePublishEligibilityService;
use Exception;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Symfony\Component\HttpFoundation\Response;
use Barryvdh\DomPDF\Facade\Pdf;


class FormController extends BaseApiController
{
    /**
     * List all forms (with optional filters).
     */
    public function getAllForms(Request $request, string $slug)
    {
        try {
            $tenant = app('tenant.context');
            $fid = $tenant->franchiseeId;
            $language = strtolower((string) $request->get('language', 'en'));
            $globalFormsLanguage = $language;
            if ($language !== 'en' && !app(TranslateTemplatePublishEligibilityService::class)->isLanguageTemplatePublished($language)) {
                $globalFormsLanguage = 'en';
            }

            $requestedLanguage = strtolower((string) $request->get('language', $tenant->lang ?? ''));
            if ($requestedLanguage === '' || $requestedLanguage === 'english') {
                $requestedLanguage = 'en';
            }

            $tenantStatus = strtolower((string) ($tenant->status ?? 'publish'));
            $statusFilter = $tenantStatus === 'draft' ? 'Draft' : 'Published';

            $translationFilter = function ($query) use ($requestedLanguage, $statusFilter, $slug) {
                // Match the requested language OR English, so a form that only has an
                // English translation is still picked up (English fallback applied below).
                $query->whereIn('language', array_values(array_unique([$requestedLanguage, 'en'])))
                    ->where('status', $statusFilter)
                    ->whereJsonContains('pages', $slug);
            };

            /** 1️⃣ Franchise forms (matched via translation) */
            $franchiseForms = collect();
            if ($fid) {
                $franchiseForms = Form::with(['translations', 'parentForm'])
                    ->where('franchisee_id', $fid)
                    ->whereHas('translations', $translationFilter)
                    ->get();

                /** Remove franchise-level duplication */
                $franchiseOverriddenParentIds = $franchiseForms
                    ->pluck('parent_form_id')
                    ->filter()
                    ->unique()
                    ->toArray();

                $franchiseForms = $franchiseForms
                    ->reject(fn(Form $form) => in_array($form->id, $franchiseOverriddenParentIds, true))
                    ->values();
            }

            $customizedParentIds = $franchiseForms
                ->pluck('parent_form_id')
                ->filter()
                ->unique()
                ->toArray();

            /** 4️⃣ Global forms (not customized) */
            $globalTranslationFilter = function ($query) use ($globalFormsLanguage, $slug) {
                // Include English so global forms without the requested-language
                // translation still resolve (English fallback applied in projectPublicForm).
                $query->whereIn('language', array_values(array_unique([$globalFormsLanguage, 'en'])))
                    ->where('status', 'Published')
                    ->whereJsonContains('pages', $slug);
            };

            $globalForms = Form::with(['translations'])
                ->where('is_global', true)
                ->whereHas('translations', $globalTranslationFilter)
                ->whereNotIn('id', $customizedParentIds)
                ->get();

            /**
             * Project each group with the status it was SELECTED with.
             *
             * Franchise forms use $statusFilter (Draft on the preview domain,
             * Published elsewhere). Global forms are always queried with
             * 'Published' above — global content has no draft variant — so they
             * must be projected as 'Published' too.
             *
             * Passing $statusFilter to both meant that on preview.youngengineers.org
             * projectPublicForm() searched global forms for a 'Draft' translation,
             * found none, returned null, and ->filter() removed them. The endpoint
             * then returned an empty array, so preview showed no form at all
             * instead of falling back to the global one.
             */
            /**
             * Start from collect() so the merges use BASE collection semantics.
             *
             * Eloquent\Collection::merge() indexes by $item->getKey(), which fatals
             * on the plain arrays projectPublicForm() returns. map() normally
             * downgrades an Eloquent collection to a base one, but only when the
             * result *contains* a non-model — an EMPTY collection contains nothing,
             * so it stays Eloquent. With a franchisee that has no forms of its own,
             * $franchiseForms is exactly that, and merging arrays into it threw a
             * PHP Error (not an Exception, so the catch below missed it) => HTTP 500.
             */
            $forms = collect()
                ->merge(
                    $franchiseForms->map(
                        fn(Form $form) => $this->projectPublicForm($form, $requestedLanguage, $slug, $statusFilter)
                    )
                )
                ->merge(
                    $globalForms->map(
                        fn(Form $form) => $this->projectPublicForm($form, $requestedLanguage, $slug, 'Published')
                    )
                )
                ->filter()
                ->values();

            return ApiResponse::success($forms, "Forms fetched successfully");

        } catch (\Exception $e) {
            return ApiResponse::error(
                'An unexpected error occurred: ' . $e->getMessage(),
                Response::HTTP_BAD_REQUEST
            );
        }
    }

    /**
     * Flatten a Form + its matching translation into the legacy public response shape.
     */
    private function projectPublicForm(Form $form, string $language, string $slug, string $status): ?array
    {
        $translations = collect($form->translations ?? []);

        $pick = function (string $lang) use ($translations, $status, $slug) {
            return $translations->first(function ($t) use ($lang, $status, $slug) {
                return strtolower((string) $t->language) === $lang
                    && (string) $t->status === $status
                    && in_array($slug, (array) ($t->pages ?? []), true);
            });
        };

        // Prefer the requested language; fall back to English when that language has
        // no translation, so the form still renders instead of returning nothing.
        $translation = $pick($language) ?? $pick('en');

        if (!$translation) {
            return null;
        }

        return [
            'id' => $form->id,
            'franchisee_id' => $form->franchisee_id,
            'parent_form_id' => $form->parent_form_id,
            'is_global' => (bool) $form->is_global,
            'order_no' => $form->order_no,
            'is_required_for_translation' => (bool) $form->is_required_for_translation,
            'translation_id' => $translation->id,
            'language' => $translation->language,
            'name' => $translation->name,
            'description' => $translation->description,
            'fields' => $translation->fields,
            'pages' => $translation->pages,
            'status' => $translation->status,
            'translated' => (bool) $translation->translated,
            'form_setting' => $translation->form_setting ?? $form->form_setting,
            'created_at' => $form->created_at,
            'updated_at' => $form->updated_at,
        ];
    }

    public function submitForms(Request $request, string $slug, FormSubmissionNotificationService $formSubmissionNotificationService)
    {
        try {
            $tenant = app('tenant.context');
            $fid = $tenant->franchiseeId;

            if (!$fid) {
                return ApiResponse::error(
                    'Franchisee context could not be resolved. Check your domain or franchiseeId parameter.',
                    Response::HTTP_UNPROCESSABLE_ENTITY
                );
            }

            $validator = Validator::make($request->all(), [
                'form_id' => 'required|string|size:36',
                'form_data' => 'required|array',
            ]);

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

            // ✅ Load form to read form_settings (email_template_id etc.)
            $form = Form::with('translations')->findOrFail($request->form_id);
            $language = strtolower((string) $request->get('language', $tenant->lang ?? 'en'));
            if ($language === '' || $language === 'english') {
                $language = 'en';
            }

            // Extract submission data (normalize currency fields to 2 decimal places)
            $submissionData = app(RegistrationPricingHelper::class)->sanitizeSubmissionData(
                collect($request->form_data)->toArray()
            );

            // Persist class_details alongside form steps so the invoice PDF,
            // PaymentAmountResolver, and notification services can read pricing
            // and programme information without re-fetching Classwise data.
            if ($request->has('class_details') && is_array($request->class_details)) {
                $submissionData['class_details'] = $request->class_details;
            }

            $zohoResult = $this->addFranchiseeLead($submissionData, $fid);
            $submissionData['zoho'] = $zohoResult;

            if (isset($submissionData['class_details'])) {
                $classwiseResult = app(ClasswiseRegistrationService::class)
                    ->registerParentStudent($submissionData);
                $submissionData['classwise'] = $classwiseResult;
            }

            // Store submission
            $submission = FormSubmission::create([
                'franchisee_id' => $fid,
                'form_id' => $request->form_id,
                'page' => $slug ?? '',
                'ip_address' => $request->ip(),
                'user_agent' => $request->userAgent(),
                'submission_data' => $submissionData,
            ]);

            // Persist policy consents (Privacy Policy + Terms of Use) if sent by the frontend.
            $this->savePolicyConsents($submission->id, $fid, $request, $submissionData);

            $pdf = Pdf::loadView('pdf.invoice', [
                'invoice' => $submission
            ]);
            $attachments = [
                [
                    '@odata.type' => '#microsoft.graph.fileAttachment',
                    'name' => "invoice-{$submission->id}.pdf",
                    'contentType' => 'application/pdf',
                    'contentBytes' => base64_encode($pdf->output()),
                ]
            ];
            // ✅ Send email based on Form->form_settings
            $emailResult = $formSubmissionNotificationService->notify(
                $form,
                $fid,
                $language,
                $submissionData,
                $attachments
            );

            return ApiResponse::success(
                [
                    "id" => $submission->id,
                    "email" => $emailResult
                ],
                "Form submitted successfully"
            );

        } catch (QueryException $e) {

            Log::error('Database Query Error', [
                'error' => $e->getMessage(),
                'sql' => $e->getSql(),
                'bindings' => $e->getBindings()
            ]);

            return ApiResponse::error('Database operation failed. Please try again.');

        } catch (\Exception $e) {
            return ApiResponse::error(
                'An unexpected error occurred: ' . $e->getMessage(),
                Response::HTTP_BAD_REQUEST
            );
        }
    }

    private function savePolicyConsents(string $submissionId, string $franchiseeId, Request $request, array $submissionData): void
    {
        // Consents come in form_data as a top-level key or inside one of the step arrays.
        $consents = $request->input('policy_consents');

        if (!is_array($consents) || empty($consents)) {
            // Fallback: check inside the submitted form_data steps.
            foreach ($submissionData as $step) {
                if (is_array($step) && isset($step['policy_consents'])) {
                    $consents = $step['policy_consents'];
                    break;
                }
            }
        }

        if (!is_array($consents) || empty($consents)) {
            return;
        }

        $allowed = ['privacy_policy', 'terms_of_use'];
        $now     = now();
        $ip      = $request->ip();

        foreach ($consents as $consent) {
            $type = $consent['type'] ?? null;
            if (!in_array($type, $allowed, true)) {
                continue;
            }

            $slug    = $type === 'privacy_policy' ? 'privacy-policy' : 'terms-of-use';
            $pageId  = Page::where('slug', $slug)->value('id');

            PolicyConsent::create([
                'submission_id' => $submissionId,
                'policy_type'   => $type,
                'page_id'       => $pageId,
                'franchisee_id' => $franchiseeId,
                'language_code' => $consent['language_code'] ?? null,
                'version'       => isset($consent['version']) ? (int) $consent['version'] : null,
                'accepted_at'   => $now,
                'ip_address'    => $ip,
            ]);
        }
    }

    /*public function submitForms(Request $request, string $slug)
    {
        try {
            $tenant = app('tenant.context');
            $fid = $tenant->franchiseeId;

            $validator = Validator::make($request->all(), [
                'form_id' => 'required|string|size:36',
            ]);

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

            // 2️⃣ Extract submission data (exclude system fields)
            $submissionData = collect($request->form_data)
                ->toArray();
            $zohoResult = $this->addFranchiseeLead($submissionData, $fid);
            $submissionData['zoho'] = $zohoResult;
            \Log::error("Zoho response data", ['data' => $submissionData]);
            // 3️⃣ Store submission
            $submission = FormSubmission::create([
                'franchisee_id' => $fid,
                'form_id' => $request->form_id,
                'page' => $slug ?? '',
                'ip_address' => $request->ip(),
                'user_agent' => $request->userAgent(),
                'submission_data' => $submissionData,
            ]);
            \Log::error("Form submit recored", ['data' => $submission]);
            return ApiResponse::success(["id" => $submission->id], "Form submitted successfully");
        } catch (QueryException $e) {
            return ApiResponse::error('Database error:' . $e->getMessage());
        } catch (\Exception $e) {
            return ApiResponse::error(
                'An unexpected error occurred: ' . $e->getMessage(),
                Response::HTTP_BAD_REQUEST
            );
        }
    }*/

    // public function getAllSubmittedFormData(Request $request)
    // {
    //     try {
    //         $tenant = app('tenant.context');
    //         $fid = $tenant->franchiseeId;
    //         $submissions = FormSubmission::with('form:id,name,pages')
    //             ->where('franchisee_id', $fid)
    //             ->latest()
    //             ->paginate(20);

    //         return response()->json([
    //             'success' => true,
    //             'data' => $submissions,
    //         ]);

    //     } catch (\Throwable $e) {

    //         logger()->error('Fetching all form submissions failed', [
    //             'franchisee_id' => $fid ?? null,
    //             'error' => $e->getMessage(),
    //         ]);

    //         return response()->json([
    //             'success' => false,
    //             'message' => $e->getMessage(),
    //         ], 500);
    //     }
    // }

    public function getByid($id)
    {
        try {
            $tenant = app('tenant.context');
            $fid = $tenant->franchiseeId;
            $columns = [
                "id",
                "submission_data",
            ];
            $submissions = FormSubmission::with([
                'payment:registration_id,status,amount,currency,payment_type,response,updated_at'
            ])
                ->select($columns)
                ->find($id);

            if (!$submissions) {
                return ApiResponse::error(
                    'Recored not based on this id for this franchisee.',
                    Response::HTTP_NOT_FOUND
                );
            }

            return ApiResponse::success([
                $submissions,
            ], "Registration invoice");

        } catch (QueryException $e) {
            return ApiResponse::error('Database error:' . $e->getMessage());
        } catch (\Throwable $e) {

            return ApiResponse::error(
                'An unexpected error occurred: ' . $e->getMessage(),
                Response::HTTP_BAD_REQUEST
            );
        }
    }

    private function addFranchiseeLead(array $data, $fid): array
    {

        // ---- 1️⃣ Basic guards (prevent undefined index errors)
        \Log::error("Zoho Paylod data", ['$data' => $data]);
        if (
            empty($data[0]['name']) ||
            empty($data[0]['email']) ||
            empty($data[0]['phone']) ||
            empty($data[1]['childs_name']) ||
            empty($data[1]['age']) ||
            empty($data[2]['select_programs'])
        ) {
            return [
                'success' => false,
                'message' => 'Invalid submission data',
            ];
        }
        $franchisee = Franchisee::where('id', $fid)->firstOrFail();
        if (empty($franchisee->email) || empty($franchisee->zoho_franchise_id)) {
            return [
                'success' => false,
                'message' => 'Zoho Lead API failed',
                'error' => 'Franchisee email or Zoho franchisee id is missing',
            ];
        }
        // ---- 2️⃣ Create Franchisee Lead
        $parts = explode(' ', trim($data[0]['name']), 2);

        $firstName = $parts[0] ?? '';
        $lastName = $parts[1] ?? '';
        $zohoPayload = [
            'data' => [
                [
                    'Name' => $data[0]['name'],
                    'Parent_First_Name' => $firstName,
                    'Parent_Last_Name' => $lastName,
                    'Email' => $data[0]['email'],
                    'Phone_Number' => $data[0]['phone'],
                    'Franchisee_Primary_Email' => $franchisee->email,
                    'Account' => $franchisee->zoho_franchise_id,
                    'Lead_Source' => 'Website',
                    'Class' => $data[2]['choose_classes'],
                    'Payment_Status' => 'Pending',
                    'Price' => '',
                ]
            ]
        ];
        try {
            $leadResponse = ZohoHelper::zohoRequest('post', 'Franchisee_Leads', $zohoPayload);
        } catch (\Throwable $e) {
            return [
                'success' => false,
                'message' => 'Zoho Lead API failed',
                'error' => $e->getMessage(),
            ];
        }

        if (($leadResponse['data'][0]['code'] ?? null) !== 'SUCCESS') {
            return [
                'success' => false,
                'message' => 'Failed to create Franchisee Lead',
                'zoho' => $leadResponse,
            ];
        }

        // ---- 3️⃣ Lead data
        $leadId = $leadResponse['data'][0]['details']['id'];
        $leadName = $data[0]['name'];
        $leadUid = 'LEAD-' . substr($leadId, -5) . '-' . strtoupper(\Str::slug($leadName, ''));

        // ---- 4️⃣ Create Child Lead
        $childPayload = [
            'data' => [
                [
                    'Name' => $data[1]['childs_name'],
                    'First_Name' => $data[1]['childs_name'],
                    'Child_Age' => $data[1]['age'],
                    'Program_Interest' => $data[2]['select_programs'],
                    'Account' => $franchisee->zoho_franchise_id,

                    'Franchisee_Leads' => [
                        'id' => $leadId,
                    ],
                ]
            ]
        ];

        try {
            $childResponse = ZohoHelper::zohoRequest('post', 'Children', $childPayload);
        } catch (\Throwable $e) {
            return [
                'success' => false,
                'message' => 'Zoho Child API failed',
                'lead' => [
                    'id' => $leadId,
                    'cw_uid' => $leadUid,
                    'name' => $leadName,
                ],
                'error' => $e->getMessage(),
            ];
        }

        if (($childResponse['data'][0]['code'] ?? null) !== 'SUCCESS') {
            return [
                'success' => false,
                'message' => 'Child creation failed',
                'lead' => [
                    'id' => $leadId,
                    'cw_uid' => $leadUid,
                    'name' => $leadName,
                ],
                'zoho' => $childResponse,
            ];
        }

        // ---- 5️⃣ Child data
        $childId = $childResponse['data'][0]['details']['id'];
        $childName = $data[1]['childs_name'];
        $childUid = 'CHILD-' . substr($childId, -5) . '-' . strtoupper(\Str::slug($childName, ''));

        // ---- 6️⃣ Final consistent response
        return [
            'success' => true,
            'lead' => [
                'id' => $leadId,
                'cw_uid' => $leadUid,
                'name' => $leadName,
            ],
            'child' => [
                'id' => $childId,
                'cw_uid' => $childUid,
                'name' => $childName,
            ],
        ];
    }

}
