<?php

namespace App\Libs\Services;

use App\Models\Form;
use App\Models\FormResponse;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Validator;
use App\Mail\FormResponseConfirmation;
use App\Mail\FormResponseSubmitted;
use Illuminate\Support\Facades\Mail;

class FormSubmissionService
{
    /**
     * Find form by slug from website_objects table
     */
    public function findFormBySlug($slug)
    {
        $form = Form::full()
            ->where('status', 'published')
            ->where('slug', $slug)
            ->with([
                'formSections' => function($query) {
                    $query->full()->orderBy('position');
                },
                'formSections.formFields' => function($query) {
                    $query->full()->orderBy('position');
                },
                'formSections.formFields.fieldOptions' => function($query) {
                    $query->full()->orderBy('position');
                }
            ])
            ->first();

        if (!$form) {
            throw new \Exception('Form not found or not published');
        }

        return $form;
    }

    /**
     * Validate form submission against form structure
     */
    public function validateSubmission(Form $form, array $data)
    {
        $rules = [];
        $messages = [];
        $attributes = [];

        $allFields = collect();
        foreach ($form->formSections as $section) {
            $allFields = $allFields->merge($section->formFields);
        }

        // Iterate through sections and then their fields
        foreach ($form->formSections as $section) {
            foreach ($section->formFields as $field) {
                $fieldName = "field_{$field->form_field_id}";
                $fieldRules = [];

                // Check conditional logic first - only validate if field should be visible
                $isFieldVisible = $this->shouldFieldBeVisible($field, $data, $allFields);

                if (!$isFieldVisible) {
                    // If field is not visible due to conditional logic, skip validation entirely
                    continue;
                }

                // Basic required validation - only apply if field is visible
                if ($field->is_mandatory) {
                    $fieldRules[] = 'required';
                } else {
                    $fieldRules[] = 'nullable';
                }

                // Field type specific validation
                switch ($field->field_type) {
                    case 'email':
                        $fieldRules[] = 'email';
                        $fieldRules[] = 'max:150';
                        break;
                    case 'text':
                        $fieldRules[] = 'string';
                        $fieldRules[] = 'max:250';
                        break;
                    case 'textarea':
                        $fieldRules[] = 'string';
                        $fieldRules[] = 'max:1000';
                        break;
                    case 'radio':
                        if ($field->fieldOptions->count() > 0) {
                            $allowedValues = $field->fieldOptions->pluck('value')->toArray();
                            $fieldRules[] = 'in:' . implode(',', $allowedValues);
                        }
                        break;
                    case 'checkbox':
                        $fieldRules[] = 'array';
                        if ($field->fieldOptions->count() > 0) {
                            $allowedValues = $field->fieldOptions->pluck('value')->toArray();
                            $fieldRules[] = 'array';
                            $rules["{$fieldName}.*"] = 'in:' . implode(',', $allowedValues);
                        }
                        break;
                    case 'members':
                        $fieldRules[] = 'integer';
                        $fieldRules[] = 'exists:members,id';
                        break;
                }

                // Apply validation rules for visible field
                $rules[$fieldName] = $fieldRules;
                $attributes[$fieldName] = $field->label;

                // Custom messages
                if ($field->is_mandatory) {
                    $messages["{$fieldName}.required"] = trans('forms.field_required', ['field' => $field->label]);
                }
                if ($field->field_type === 'email') {
                    $messages["{$fieldName}.email"] = trans('forms.field_email', ['field' => $field->label]);
                }
            }
        }

        $validator = Validator::make($data, $rules, $messages, $attributes);

        if ($validator->fails()) {
            throw new ValidationException($validator);
        }

        return $validator->validated();
    }

    /**
     * Check if field should be visible based on conditional logic
     */
    private function shouldFieldBeVisible($field, array $data, $allFields = null)
    {
        // If no conditional dependency, always visible
        if (!$field->conditional_field_dependent_id) {
            return true;
        }

        // Get all fields if not provided
        if ($allFields === null) {
            // Collect all fields from form sections
            $allFields = collect();
            if ($field->section && $field->section->form) {
                foreach ($field->section->form->sections as $section) {
                    $allFields = $allFields->merge($section->fields);
                }
            }
        }

        // Find the parent field by searching which field has an option with conditional_field_parent_id
        // that matches our field's conditional_field_dependent_id
        $parentField = null;
        $triggeringOption = null;

        foreach ($allFields as $potentialParent) {
            if ($potentialParent->fieldOptions && $potentialParent->fieldOptions->count() > 0) {
                // Look for an option that has conditional_field_parent_id matching our dependent_id
                $matchingOption = $potentialParent->fieldOptions->where('conditional_field_parent_id', $field->conditional_field_dependent_id)->first();

                if ($matchingOption) {
                    $parentField = $potentialParent;
                    $triggeringOption = $matchingOption;
                    break;
                }
            }
        }

        if (!$parentField) {
            return true; // If parent not found, show field by default
        }

        $parentFieldName = "field_{$parentField->form_field_id}";
        $submittedValue = $data[$parentFieldName] ?? null;

        // Check if the triggering option is selected
        if ($triggeringOption) {
            // Check if this specific option value is selected in the parent field
            if (is_array($submittedValue)) {
                $isSelected = in_array($triggeringOption->value, $submittedValue);
            } else {
                $isSelected = $submittedValue == $triggeringOption->value;
            }

            return $isSelected;
        } // Fallback: basic conditional logic for fields without specific options
        if (is_array($submittedValue)) {
            return !empty($submittedValue); // Show if checkbox has selections
        }

        return !empty($submittedValue); // Show if parent field has any value
    }

    /**
     * Save form response
     */
    public function saveResponse(Form $form, array $validatedData)
    {
        return FormResponse::create([
            'form_id' => $form->id,
            'responses' => $validatedData,
        ]);
    }

    /**
     * Find the members-type field in the form and return it along with its submitted value.
     * Returns null if no members field is present or has a value.
     */
    private function findMemberFieldData(Form $form, array $data): ?array
    {
        foreach ($form->formSections as $section) {
            foreach ($section->formFields as $field) {
                if ($field->field_type === 'members') {
                    $key = "field_{$field->form_field_id}";
                    $value = $data[$key] ?? null;
                    if (!empty($value)) {
                        return ['field' => $field, 'key' => $key, 'value' => $value];
                    }
                }
            }
        }
        return null;
    }

    /**
     * Find the first email-type field in the form and return it along with its submitted value.
     * Returns null if no email field is present or has a value.
     */
    private function findEmailFieldData(Form $form, array $data): ?array
    {
        foreach ($form->formSections as $section) {
            foreach ($section->formFields as $field) {
                if ($field->field_type === 'email') {
                    $key = "field_{$field->form_field_id}";
                    $value = $data[$key] ?? null;
                    if (!empty($value)) {
                        return ['field' => $field, 'key' => $key, 'value' => $value];
                    }
                }
            }
        }
        return null;
    }

    /**
     * Process complete form submission
     */
    public function processSubmission($slug, array $data)
    {
        // Find form by slug
        $form = $this->findFormBySlug($slug);

        // Find the first email field in the submission
        $emailFieldData = $this->findEmailFieldData($form, $data);

        // Check for duplicate email and/or company submissions on this form, reporting all errors at once
        $duplicateErrors = [];

        if ($emailFieldData) {
            $alreadyRegistered = FormResponse::where('form_id', $form->id)
                ->where('status', '!=', FormResponse::STATUS_CANCELLED)
                ->where('responses->' . $emailFieldData['key'], $emailFieldData['value'])
                ->exists();

            if ($alreadyRegistered) {
                $duplicateErrors[$emailFieldData['key']] = [trans('forms.already_registered_email')];
            }
        }

        $memberFieldData = $this->findMemberFieldData($form, $data);
        if ($memberFieldData) {
            $companyAlreadyRegistered = FormResponse::where('form_id', $form->id)
                ->where('status', '!=', FormResponse::STATUS_CANCELLED)
                ->where('responses->' . $memberFieldData['key'], $memberFieldData['value'])
                ->exists();

            if ($companyAlreadyRegistered) {
                $duplicateErrors[$memberFieldData['key']] = [trans('forms.already_registered_member')];
            }
        }

        if (!empty($duplicateErrors)) {
            throw ValidationException::withMessages($duplicateErrors);
        }

        // Validate submission
        $validatedData = $this->validateSubmission($form, $data);

        // Save response
        $formSaved = $this->saveResponse($form, $validatedData);

        $this->sendEmailForm($formSaved);

        // Send confirmation email to the user if an email field was present
        if ($emailFieldData) {
            $this->sendConfirmationEmail($form, $formSaved, $emailFieldData['value'], $validatedData);
        }

        return [
            'success' => true,
            'message' => 'Form submitted successfully',
            'formTitle' => $form->title
        ];
    }

    public function sendEmailForm(FormResponse $formResponse)
    {
        Mail::to(config('mail.contact.block_form_address'))
            ->send(new FormResponseSubmitted($formResponse));
    }

    public function sendConfirmationEmail(Form $form, FormResponse $formResponse, string $email, array $submissionData)
    {
        Mail::to($email)
            ->send(new FormResponseConfirmation($form, $formResponse, $email, $submissionData));
    }
}
