<?php

namespace App\Http\Controllers\Inquiry;

use App\Http\Controllers\ApiController;
use App\Http\Requests\Inquiry\SubmitOutboundInquiryRequest;
use App\Models\Agent;
use App\Models\City;
use App\Models\CityTranslation;
use App\Models\Inquiry;
use App\Models\Language;
use App\Models\Person;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;
use Throwable;

/**
 * @OA\Post(
 *   path="/api/inquiry/outbound",
 *   tags={"Inquiry"},
 *   summary="Submit Outbound Insurance Inquiry",
 *   operationId="submit_outbound_inquiry",
 *   security={{"auth":{}}},
 *
 *   @OA\Parameter(name="Accept-Language", in="header", description="Accept-Language", required=true, example="en", @OA\Schema(type="string")),
 *   @OA\Parameter(name="API-Key", in="header", description="API-Key", required=true, example="", @OA\Schema(type="string")),
 *
 *   @OA\RequestBody(
 *     required=true,
 *     @OA\MediaType(
 *       mediaType="application/x-www-form-urlencoded",
 *       @OA\Schema(
 *         required={"address", "birthdays", "city", "deductible_ids", "email", "ended_at", "first_names", "genders", "insurance_cover", "last_names", "phone", "postal_code", "price_ids", "province_id", "started_at", "destination"},
 *         @OA\Property(property="address", type="string", description="Address", example="123 Main St"),
 *         @OA\Property(property="birthdays", type="string", description="Birthdays CSV (YYYY-MM-DD)", example="1980-05-15,1985-08-20"),
 *         @OA\Property(property="city", type="string", description="City Name", example="Toronto"),
 *         @OA\Property(property="deductible_ids", type="string", description="Deductible IDs CSV", example="1,2"),
 *         @OA\Property(property="email", type="string", description="Email", example="john@example.com"),
 *         @OA\Property(property="ended_at", type="string", description="End Date (YYYY-MM-DD)", example="2025-04-15"),
 *         @OA\Property(property="first_names", type="string", description="First Names CSV", example="John,Jane"),
 *         @OA\Property(property="genders", type="string", description="Genders CSV (Male,Female)", example="Male,Female"),
 *         @OA\Property(property="insurance_cover", type="integer", description="Insurance Coverage Amount", example=100000),
 *         @OA\Property(property="last_names", type="string", description="Last Names CSV", example="Doe,Smith"),
 *         @OA\Property(property="phone", type="string", description="Phone Number", example="+14165551212"),
 *         @OA\Property(property="postal_code", type="string", description="Postal Code", example="M5H 2N2"),
 *         @OA\Property(property="price_ids", type="string", description="Price IDs CSV", example="100,101"),
 *         @OA\Property(property="province_id", type="integer", description="Province ID", example=1),
 *         @OA\Property(property="started_at", type="string", description="Start Date (YYYY-MM-DD)", example="2025-04-01"),
 *         @OA\Property(property="destination", type="string", description="Destination", example="worldwide_including_usa"),
 *         @OA\Property(property="trip_purpose", type="string", description="Trip Purpose", example="tourism"),
 *         @OA\Property(property="destination_country", type="string", description="Destination Country", example="United States"),
 *         @OA\Property(property="message", type="string", description="Additional Message", example="Special requests"),
 *         @OA\Property(property="card_number", type="string", description="Card Number", example="4111111111111111"),
 *         @OA\Property(property="card_cvv", type="string", description="Card CVV", example="123"),
 *         @OA\Property(property="card_name", type="string", description="Card Holder Name", example="John Doe"),
 *         @OA\Property(property="card_expiration", type="string", description="Card Expiration (YYYY-MM)", example="2026-12"),
 *         @OA\Property(property="transfer_password", type="string", description="Transfer Password", example="password123"),
 *         @OA\Property(property="base_premium", type="number", description="Base Premium", example=131.25),
 *         @OA\Property(property="total_premium", type="number", description="Total Premium", example=131.25),
 *         @OA\Property(property="tax_amount", type="number", description="Tax Amount", example=0),
 *         @OA\Property(property="final_amount", type="number", description="Final Amount", example=131.25),
 *         @OA\Property(property="has_smoking_surcharge", type="boolean", description="Has Smoking Surcharge", example=false),
 *         @OA\Property(property="canada_half_price_applied", type="boolean", description="Canada Half Price Applied", example=false),
 *         @OA\Property(property="questionnaire_required", type="boolean", description="Questionnaire Required", example=false),
 *         @OA\Property(property="questionnaire_completed", type="boolean", description="Questionnaire Completed", example=false),
 *         @OA\Property(property="questionnaire_answers", type="string", description="Questionnaire Answers JSON", example="{}"),
 *         @OA\Property(property="rate_categories", type="string", description="Rate Categories CSV", example="A,B"),
 *         @OA\Property(property="has_pre_existing_conditions", type="string", description="Pre-existing Conditions CSV", example="false,false"),
 *         @OA\Property(property="is_smokers", type="string", description="Smoker Status CSV", example="false,true"),
 *         @OA\Property(property="deductible_amounts", type="string", description="Deductible Amounts CSV", example="0,0"),
 *         @OA\Property(property="questionnaire_completions", type="string", description="Questionnaire Completions CSV", example="false,false"),
 *         @OA\Property(property="questionnaire_data", type="string", description="Questionnaire Data JSON", example="{}")
 *       )
 *     )
 *   ),
 *
 *   @OA\Response(
 *     response=200,
 *     description="Success",
 *     @OA\JsonContent(
 *       type="object",
 *       @OA\Property(property="result", type="object",
 *         @OA\Property(property="inquiry_id", type="string", example="01JMFX2XYZABCDEFGHIJKLMNOP"),
 *         @OA\Property(property="reference_number", type="string", example="INQ-ABC12345"),
 *         @OA\Property(property="status", type="string", example="pending"),
 *         @OA\Property(property="submitted_at", type="string", example="2024-03-21 10:30:00"),
 *         @OA\Property(property="total_premium", type="number", format="float", example=131.25),
 *         @OA\Property(property="final_amount", type="number", format="float", example=131.25),
 *         @OA\Property(property="number_of_people", type="integer", example=2),
 *         @OA\Property(property="questionnaire_required", type="boolean", example=false),
 *         @OA\Property(property="questionnaire_completed", type="boolean", example=false),
 *         @OA\Property(property="next_steps", type="array",
 *           @OA\Items(type="string", example="Your inquiry has been submitted successfully.")
 *         )
 *       )
 *     )
 *   ),
 *   @OA\Response(response=400, description="Bad Request"),
 *   @OA\Response(response=401, description="Unauthorized"),
 *   @OA\Response(response=422, description="Validation Error"),
 *   @OA\Response(response=500, description="Internal Server Error")
 * )
 */
class SubmitOutboundInquiryController extends ApiController
{
    /**
     * Handle the incoming request.
     */
    public function __invoke(SubmitOutboundInquiryRequest $request): JsonResponse
    {
        try {
            DB::beginTransaction();
            
            $data = $request->validatedData();
            
            // Validate array counts match
            $this->validateArrayCounts($data);
            
            // Get or create city
            $cityId = $this->getOrCreateCity($data);
            
            // Create inquiry
            $inquiry = $this->createInquiry($data, $cityId);
            
            // Create people records
            $this->createPeople($inquiry, $data);
            
            // Update inquiry with calculated values
            $this->updateInquiryCalculations($inquiry);
            
            // Log the submission
            $this->logSubmission($inquiry, $data);
            
            DB::commit();
            
            return $this->success($this->prepareResponse($inquiry));
            
        } catch (Throwable $e) {
            DB::rollBack();
            Log::error('Outbound inquiry submission failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'data' => $request->except(['card_number', 'card_cvv', 'transfer_password']),
            ]);
            
            return $this->error(
                'Failed to submit inquiry: ' . $e->getMessage(),
                [],
                $e->getCode() ?: Response::HTTP_INTERNAL_SERVER_ERROR
            );
        }
    }

    /**
     * Validate that all arrays have the same count.
     */
    private function validateArrayCounts(array $data): void
    {
        $arraysToCheck = [
            'birthdays',
            'first_names',
            'last_names',
            'genders',
            'deductible_ids',
            'price_ids',
        ];
        
        $count = null;
        $arrayNames = [];
        
        foreach ($arraysToCheck as $arrayName) {
            if (!isset($data[$arrayName]) || !is_array($data[$arrayName])) {
                throw new Exception("Missing or invalid array: {$arrayName}", Response::HTTP_BAD_REQUEST);
            }
            
            $currentCount = count($data[$arrayName]);
            
            if ($count === null) {
                $count = $currentCount;
            } elseif ($currentCount !== $count) {
                $arrayNames[] = $arrayName;
            }
        }
        
        if (!empty($arrayNames)) {
            throw new Exception(
                sprintf(
                    'Array counts do not match. Expected %d items, but found mismatches in: %s',
                    $count,
                    implode(', ', $arrayNames)
                ),
                Response::HTTP_BAD_REQUEST
            );
        }
    }

    /**
     * Get or create city record.
     */
    private function getOrCreateCity(array $data): int
    {
        $cityName = trim($data['city']);
        
        // Try to find existing city translation
        $cityTranslation = CityTranslation::where('name', $cityName)->first();
        
        if ($cityTranslation) {
            return $cityTranslation->city_id;
        }
        
        // Create new city
        $city = City::create([
            'province_id' => $data['province_id'],
            'slug' => Str::slug($cityName) . '-' . (City::max('id') ?? 0) + 1,
        ]);
        
        // Create translations for all languages
        $languages = Language::all();
        
        foreach ($languages as $language) {
            CityTranslation::create([
                'city_id' => $city->id,
                'language_id' => $language->id,
                'name' => $cityName,
                'is_active' => true,
            ]);
        }
        
        return $city->id;
    }

    /**
     * Create inquiry record.
     */
    private function createInquiry(array $data, int $cityId): Inquiry
    {
        // Get agent ID from API key
        $agentId = Agent::where('id', $data['apiKey'])->value('id');
        
        if (!$agentId) {
            throw new Exception('Invalid API key', Response::HTTP_UNAUTHORIZED);
        }
        
        // Parse card expiration if provided
        $cardExpiration = null;
        if (!empty($data['card_expiration'])) {
            try {
                $expDate = Carbon::parse($data['card_expiration']);
                $cardExpiration = $expDate->format('ym'); // Format as YYMM
            } catch (\Exception $e) {
                // Leave as null if parsing fails
            }
        }
        
        // Calculate trip duration
        $startDate = Carbon::parse($data['started_at']);
        $endDate = Carbon::parse($data['ended_at']);
        $tripDuration = $endDate->diffInDays($startDate) + 1;
        
        // Determine if questionnaire is required
        $questionnaireRequired = $this->isQuestionnaireRequired($data);
        
        // Create inquiry
        return Inquiry::create([
            'agent_id' => $agentId,
            'city_id' => $cityId,
            'insurance_cover' => $data['insurance_cover'],
            'destination' => $data['destination'],
            'trip_duration' => $tripDuration,
            'base_premium' => $data['base_premium'] ?? 0,
            'total_premium' => $data['total_premium'] ?? 0,
            'tax_amount' => $data['tax_amount'] ?? 0,
            'final_amount' => $data['final_amount'] ?? 0,
            'address' => $data['address'],
            'postal_code' => $data['postal_code'],
            'phone' => $data['phone'],
            'email' => $data['email'],
            'card_number' => $data['card_number'] ?? null,
            'card_cvv' => $data['card_cvv'] ?? null,
            'card_name' => $data['card_name'] ?? null,
            'card_expiration' => $cardExpiration,
            'transfer_password' => $data['transfer_password'] ?? null,
            'message' => $data['message'] ?? null,
            'beneficiary_first_name' => $data['first_names'][0] ?? '',
            'beneficiary_last_name' => $data['last_names'][0] ?? '',
            'beneficiary_born_at' => !empty($data['birthdays'][0]) ? Carbon::parse($data['birthdays'][0]) : null,
            'started_at' => $startDate,
            'ended_at' => $endDate,
            'arrived_at' => $startDate, // For outbound, arrived_at is same as started_at
            'inquired_at' => now(),
            'local_submitted_at' => now(),
            'is_beneficiary_male' => ($data['genders'][0] ?? 'Male') === 'Male',
            'is_entry' => false, // Outbound insurance
            'is_deal' => false,
            'canada_half_price_applied' => $data['canada_half_price_applied'] ?? false,
            'has_smoking_surcharge' => $data['has_smoking_surcharge'] ?? false,
            'questionnaire_required' => $questionnaireRequired,
            'questionnaire_completed' => $data['questionnaire_completed'] ?? false,
            'questionnaire_answers' => $data['questionnaire_answers'] ?? null,
            'questionnaire_completed_at' => $data['questionnaire_completed'] ? now() : null,
            'status' => Inquiry::STATUS_PENDING,
            'number_of_people' => count($data['first_names']),
            'trip_purpose' => $data['trip_purpose'] ?? Inquiry::PURPOSE_TOURISM,
            'destination_country' => $data['destination_country'] ?? null,
        ]);
    }

    /**
     * Determine if questionnaire is required based on ages.
     */
    private function isQuestionnaireRequired(array $data): bool
    {
        if (isset($data['questionnaire_required'])) {
            return (bool) $data['questionnaire_required'];
        }
        
        // Check if any person is 60+
        foreach ($data['birthdays'] as $birthday) {
            $age = Carbon::parse($birthday)->diffInYears(now());
            if ($age >= 60) {
                return true;
            }
        }
        
        return false;
    }

    /**
     * Create people records.
     */
    private function createPeople(Inquiry $inquiry, array $data): void
    {
        $count = count($data['first_names']);
        
        for ($i = 0; $i < $count; $i++) {
            // Calculate age
            $age = null;
            if (!empty($data['birthdays'][$i])) {
                $birthDate = Carbon::parse($data['birthdays'][$i]);
                $age = $birthDate->diffInYears(now());
            }
            
            // Get individual data if provided
            $individualPremium = $data['individual_premiums'][$i] ?? null;
            $rateCategory = $data['rate_categories'][$i] ?? Person::RATE_CATEGORY_A;
            $hasSmokingSurcharge = $data['has_smoking_surcharges'][$i] ?? false;
            $isEligible = $data['is_eligible_persons'][$i] ?? true;
            $ineligibilityReason = $data['ineligibility_reasons'][$i] ?? null;
            $hasPreExistingConditions = $data['has_pre_existing_conditions'][$i] ?? false;
            $isSmoker = $data['is_smokers'][$i] ?? false;
            $deductibleAmount = $data['deductible_amounts'][$i] ?? 0;
            $questionnaireCompleted = $data['questionnaire_completions'][$i] ?? false;
            $questionnaireData = $data['questionnaire_data'][$i] ?? null;
            
            // Determine if person requires questionnaire
            $requiresQuestionnaire = $age >= 60;
            
            Person::create([
                'id' => Str::ulid()->toString(),
                'inquiry_id' => $inquiry->id,
                'deductible_id' => $data['deductible_ids'][$i],
                'price_id' => $data['price_ids'][$i],
                'first_name' => $data['first_names'][$i],
                'last_name' => $data['last_names'][$i],
                'born_at' => !empty($data['birthdays'][$i]) ? Carbon::parse($data['birthdays'][$i]) : null,
                'age' => $age,
                'is_male' => ($data['genders'][$i] ?? 'Male') === 'Male',
                'individual_premium' => $individualPremium,
                'rate_category' => $rateCategory,
                'has_smoking_surcharge' => $hasSmokingSurcharge,
                'is_eligible' => $isEligible,
                'ineligibility_reason' => $ineligibilityReason,
                'has_pre_existing_conditions' => $hasPreExistingConditions,
                'is_smoker' => $isSmoker,
                'deductible_amount' => $deductibleAmount,
                'questionnaire_completed' => $questionnaireCompleted,
                'questionnaire_data' => $questionnaireData,
                'questionnaire_completed_at' => $questionnaireCompleted ? now() : null,
            ]);
        }
    }

    /**
     * Update inquiry with calculated values.
     */
    private function updateInquiryCalculations(Inquiry $inquiry): void
    {
        // Recalculate total premium from people if not provided
        if (empty($inquiry->total_premium) || $inquiry->total_premium == 0) {
            $totalPremium = 0;
            
            foreach ($inquiry->people as $person) {
                if ($person->individual_premium) {
                    $totalPremium += $person->individual_premium;
                }
            }
            
            if ($totalPremium > 0) {
                $inquiry->total_premium = $totalPremium;
                $inquiry->final_amount = $totalPremium + $inquiry->tax_amount;
            }
        }
        
        // Update number of people
        $inquiry->number_of_people = $inquiry->people->count();
        
        // Update questionnaire status
        $questionnaireCompleted = true;
        foreach ($inquiry->people as $person) {
            if ($person->age >= 60 && !$person->questionnaire_completed) {
                $questionnaireCompleted = false;
                break;
            }
        }
        
        $inquiry->questionnaire_completed = $questionnaireCompleted;
        if ($questionnaireCompleted && !$inquiry->questionnaire_completed_at) {
            $inquiry->questionnaire_completed_at = now();
        }
        
        $inquiry->save();
    }

    /**
     * Log the submission.
     */
    private function logSubmission(Inquiry $inquiry, array $data): void
    {
        Log::info('Outbound insurance inquiry submitted', [
            'inquiry_id' => $inquiry->id,
            'reference_number' => $inquiry->reference_number,
            'agent_id' => $inquiry->agent_id,
            'number_of_people' => $inquiry->number_of_people,
            'destination' => $inquiry->destination,
            'total_premium' => $inquiry->total_premium,
            'questionnaire_required' => $inquiry->questionnaire_required,
            'questionnaire_completed' => $inquiry->questionnaire_completed,
            'ip_address' => request()->ip(),
            'user_agent' => request()->userAgent(),
        ]);
    }

    /**
     * Prepare response data.
     */
    private function prepareResponse(Inquiry $inquiry): array
    {
        $nextSteps = [
            'Your outbound insurance inquiry has been submitted successfully.',
            'Reference number: ' . $inquiry->reference_number,
        ];
        
        if ($inquiry->questionnaire_required && !$inquiry->questionnaire_completed) {
            $nextSteps[] = 'Medical questionnaire is required for age 60+. Please complete the questionnaire to finalize your insurance.';
        }
        
        $nextSteps[] = 'Our team will review your inquiry and contact you if needed.';
        $nextSteps[] = 'You can track the status of your inquiry using your reference number.';
        
        return [
            'inquiry_id' => $inquiry->id,
            'reference_number' => $inquiry->reference_number,
            'status' => $inquiry->status,
            'status_label' => $inquiry->getStatusFormatted(),
            'submitted_at' => $inquiry->inquired_at->format('Y-m-d H:i:s'),
            'local_submitted_at' => $inquiry->local_submitted_at->format('Y-m-d H:i:s'),
            'total_premium' => (float) $inquiry->total_premium,
            'total_premium_formatted' => $inquiry->getTotalPremiumFormatted(),
            'final_amount' => (float) $inquiry->final_amount,
            'final_amount_formatted' => $inquiry->getFinalAmountFormatted(),
            'number_of_people' => $inquiry->number_of_people,
            'destination' => $inquiry->destination,
            'destination_label' => $inquiry->getDestinationLabel(),
            'trip_purpose' => $inquiry->trip_purpose,
            'trip_purpose_label' => $inquiry->getTripPurposeLabel(),
            'trip_duration' => $inquiry->trip_duration ?? $inquiry->getInsuranceDays(),
            'start_date' => $inquiry->started_at->format('Y-m-d'),
            'end_date' => $inquiry->ended_at->format('Y-m-d'),
            'questionnaire_required' => $inquiry->questionnaire_required,
            'questionnaire_completed' => $inquiry->questionnaire_completed,
            'questionnaire_completed_at' => $inquiry->questionnaire_completed_at?->format('Y-m-d H:i:s'),
            'next_steps' => $nextSteps,
            'people_summary' => [
                'total' => $inquiry->number_of_people,
                'requiring_questionnaire' => $inquiry->getPeopleNeedingQuestionnaire()->count(),
                'completed_questionnaire' => $inquiry->people->where('questionnaire_completed', true)->count(),
            ],
        ];
    }
}