<?php

namespace App\Http\Controllers\Inquiry;

use App\Http\Controllers\ApiController;
use App\Http\Requests\Inquiry\GetQuestionnaireRequest;
use App\Models\Person;
use App\Models\QuestionnaireAnswer;
use App\Models\Inquiry;
use App\Enums\QuestionnaireStep;
use App\Services\QuestionnaireService;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Throwable;

/**
 * @OA\Get(
 *   path="/api/inquiry/questionnaire",
 *   tags={"Questionnaire"},
 *   summary="Get medical questionnaire for a person",
 *   operationId="get_questionnaire",
 *   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\Parameter(name="inquiry_id", in="query", description="Inquiry ID", required=true, example="01JMFX2XYZABCDEFGHIJKLMNOP"),
 *   @OA\Parameter(name="person_id", in="query", description="Person ID (optional, defaults to first person needing questionnaire)", required=false, example="01JMFX2XYZABCDEFGHIJKLMNOP"),
 *   @OA\Parameter(name="step", in="query", description="Questionnaire step (1-4)", required=false, example=1),
 *   @OA\Parameter(name="reset", in="query", description="Reset questionnaire if exists", required=false, example=false),
 *   
 *   @OA\Response(
 *     response=200,
 *     description="Success",
 *     @OA\JsonContent(
 *       type="object",
 *       @OA\Property(property="result", type="object",
 *         @OA\Property(property="questionnaire", type="object",
 *           @OA\Property(property="questionnaire_id", type="string", example="01JMFX2XYZABCDEFGHIJKLMNOP"),
 *           @OA\Property(property="person_id", type="string", example="01JMFX2XYZABCDEFGHIJKLMNOP"),
 *           @OA\Property(property="person_name", type="string", example="John Doe"),
 *           @OA\Property(property="age", type="integer", example=65),
 *           @OA\Property(property="requires_questionnaire", type="boolean", example=true),
 *           @OA\Property(property="current_step", type="integer", example=1),
 *           @OA\Property(property="total_steps", type="integer", example=4),
 *           @OA\Property(property="completion_percentage", type="integer", example=25),
 *           @OA\Property(property="status", type="string", example="in_progress"),
 *           @OA\Property(property="questions", type="array",
 *             @OA\Items(type="object",
 *               @OA\Property(property="step", type="integer", example=1),
 *               @OA\Property(property="step_label", type="string", example="Eligibility Check"),
 *               @OA\Property(property="questions", type="array",
 *                 @OA\Items(type="object",
 *                   @OA\Property(property="id", type="string", example="heart_surgery_10y"),
 *                   @OA\Property(property="text", type="string", example="Have you had a heart bypass, coronary angioplasty, or heart valve surgery more than 10 years ago?"),
 *                   @OA\Property(property="type", type="string", example="yes_no"),
 *                   @OA\Property(property="help_text", type="string", example="If unsure, consult your doctor before answering."),
 *                   @OA\Property(property="answer", type="string", example=null),
 *                   @OA\Property(property="answered_at", type="string", example=null)
 *                 )
 *               )
 *             )
 *           ),
 *           @OA\Property(property="summary", type="object",
 *             @OA\Property(property="eligible", type="boolean", example=true),
 *             @OA\Property(property="rate_category", type="string", example=null),
 *             @OA\Property(property="has_smoking_surcharge", type="boolean", example=false),
 *             @OA\Property(property="started_at", type="string", example="2024-03-21 10:30:00"),
 *             @OA\Property(property="completed_at", type="string", example=null)
 *           ),
 *           @OA\Property(property="navigation", type="object",
 *             @OA\Property(property="can_go_back", type="boolean", example=false),
 *             @OA\Property(property="can_skip_step", type="boolean", example=false),
 *             @OA\Property(property="next_step_available", type="boolean", example=true),
 *             @OA\Property(property="max_step_reached", type="integer", example=1)
 *           ),
 *           @OA\Property(property="warnings", type="array",
 *             @OA\Items(type="string", example="Any 'Yes' answer in Step 1 will make you ineligible for insurance.")
 *           )
 *         )
 *       )
 *     )
 *   ),
 *   @OA\Response(response=400, description="Bad Request"),
 *   @OA\Response(response=404, description="Not Found"),
 *   @OA\Response(response=422, description="Validation Error")
 * )
 */
class GetQuestionnaireController extends ApiController
{
    /**
     * @var QuestionnaireService
     */
    private $questionnaireService;

    /**
     * Constructor
     */
    public function __construct(QuestionnaireService $questionnaireService)
    {
        $this->questionnaireService = $questionnaireService;
    }

    /**
     * Handle the incoming request.
     */
    public function __invoke(GetQuestionnaireRequest $request): JsonResponse
    {
        try {
            DB::beginTransaction();
            
            $validated = $request->validated();
            
            // Find the inquiry
            $inquiry = Inquiry::find($validated['inquiry_id']);
            if (!$inquiry) {
                return $this->error('Inquiry not found', [], 404);
            }
            
            // Find or select the person
            $person = $this->findOrSelectPerson($inquiry, $validated);
            if (!$person) {
                return $this->error('No person found requiring questionnaire', [], 404);
            }
            
            // Check if person requires questionnaire
            if (!$person->requiresQuestionnaire()) {
                return $this->error('This person does not require a medical questionnaire', [], 400);
            }
            
            // Get or create questionnaire answer
            $questionnaire = $this->getOrCreateQuestionnaire($person, $inquiry, $validated);
            
            // Get the requested step or determine current step
            $requestedStep = $validated['step'] ?? null;
            $currentStep = $this->determineCurrentStep($questionnaire, $requestedStep);
            
            // Get questions for the current step
            $questions = $this->getQuestionsForStep($currentStep, $questionnaire);
            
            // Prepare response data
            $response = $this->prepareResponse($inquiry, $person, $questionnaire, $currentStep, $questions);
            
            DB::commit();
            
            return $this->success(['questionnaire' => $response]);
            
        } catch (Throwable $e) {
            DB::rollBack();
            return $this->error($e->getMessage(), [], $e->getCode() ?: 500);
        }
    }

    /**
     * Find or select person for questionnaire.
     */
    private function findOrSelectPerson(Inquiry $inquiry, array $validated): ?Person
    {
        // If person_id is provided, find that person
        if (!empty($validated['person_id'])) {
            $person = $inquiry->people()->where('id', $validated['person_id'])->first();
            if ($person && $person->requiresQuestionnaire()) {
                return $person;
            }
        }
        
        // Find first person needing questionnaire
        return $inquiry->people->first(function (Person $person) {
            return $person->requiresQuestionnaire() && !$person->questionnaire_completed;
        });
    }

    /**
     * Get or create questionnaire answer.
     */
    private function getOrCreateQuestionnaire(Person $person, Inquiry $inquiry, array $validated): QuestionnaireAnswer
    {
        // Check if questionnaire already exists
        $questionnaire = QuestionnaireAnswer::where('person_id', $person->id)->first();
        
        // Reset if requested and exists
        if ($questionnaire && ($validated['reset'] ?? false)) {
            $questionnaire->reset();
            $questionnaire->refresh();
        }
        
        // Create new if doesn't exist
        if (!$questionnaire) {
            $questionnaire = QuestionnaireAnswer::create([
                'person_id' => $person->id,
                'inquiry_id' => $inquiry->id,
                'status' => 'in_progress',
                'started_at' => now(),
            ]);
            
            // Update person's questionnaire status
            $person->questionnaire_completed = false;
            $person->save();
        }
        
        return $questionnaire;
    }

    /**
     * Determine current step for questionnaire.
     */
    private function determineCurrentStep(QuestionnaireAnswer $questionnaire, ?int $requestedStep): QuestionnaireStep
    {
        // If step is requested and valid, use it
        if ($requestedStep && $requestedStep >= 1 && $requestedStep <= 4) {
            return QuestionnaireStep::from($requestedStep);
        }
        
        // Determine current step based on progress
        if (!$questionnaire->step1_answers) {
            return QuestionnaireStep::ELIGIBILITY;
        }
        
        if (!$questionnaire->step1_passed) {
            return QuestionnaireStep::ELIGIBILITY;
        }
        
        if (!$questionnaire->step2_answers) {
            return QuestionnaireStep::RATE_C_TRIGGER;
        }
        
        if (!$questionnaire->step3_answers) {
            return QuestionnaireStep::RATE_B_TRIGGER;
        }
        
        if (!$questionnaire->step4_answers) {
            return QuestionnaireStep::SMOKING;
        }
        
        // All steps completed
        return QuestionnaireStep::SMOKING;
    }

    /**
     * Get questions for a specific step.
     */
    private function getQuestionsForStep(QuestionnaireStep $step, QuestionnaireAnswer $questionnaire): array
    {
        $questions = $this->questionnaireService->getQuestionsForStep($step);
        
        // Add existing answers if any
        $answerField = match($step) {
            QuestionnaireStep::ELIGIBILITY => 'step1_answers',
            QuestionnaireStep::RATE_C_TRIGGER => 'step2_answers',
            QuestionnaireStep::RATE_B_TRIGGER => 'step3_answers',
            QuestionnaireStep::SMOKING => 'step4_answers',
        };
        
        $existingAnswers = $questionnaire->$answerField ?? [];
        
        // Enhance questions with existing answers
        foreach ($questions as &$question) {
            $questionId = $question['code'] ?? null;
            if ($questionId && isset($existingAnswers[$questionId])) {
                $question['answer'] = $existingAnswers[$questionId];
                $question['answered'] = true;
            } else {
                $question['answer'] = null;
                $question['answered'] = false;
            }
        }
        
        return [
            'step' => $step->value,
            'step_label' => $step->label(),
            'step_description' => $step->description(),
            'questions' => $questions,
        ];
    }

    /**
     * Prepare response data.
     */
    private function prepareResponse(
        Inquiry $inquiry,
        Person $person,
        QuestionnaireAnswer $questionnaire,
        QuestionnaireStep $currentStep,
        array $questions
    ): array {
        // Calculate completion percentage
        $completionPercentage = $questionnaire->getCompletionPercentage();
        
        // Determine max step reached
        $maxStepReached = 1;
        if ($questionnaire->step1_answers) $maxStepReached = 1;
        if ($questionnaire->step2_answers) $maxStepReached = 2;
        if ($questionnaire->step3_answers) $maxStepReached = 3;
        if ($questionnaire->step4_answers) $maxStepReached = 4;
        
        // Navigation flags
        $canGoBack = $currentStep->value > 1;
        $canSkipStep = false; // Generally cannot skip medical questions
        $nextStepAvailable = $currentStep->value < 4;
        
        // Warnings and instructions
        $warnings = $this->getWarningsForStep($currentStep);
        
        // Summary of current status
        $summary = [
            'eligible' => $questionnaire->isEligible(),
            'rate_category' => $questionnaire->rate_category,
            'has_smoking_surcharge' => $questionnaire->is_smoker || $questionnaire->uses_vaping,
            'started_at' => $questionnaire->started_at?->format('Y-m-d H:i:s'),
            'completed_at' => $questionnaire->completed_at?->format('Y-m-d H:i:s'),
            'status' => $questionnaire->status,
            'status_label' => $questionnaire->getStatusFormatted(),
        ];
        
        // People still needing questionnaire
        $remainingPeople = $inquiry->people
            ->filter(function (Person $p) use ($person) {
                return $p->id !== $person->id && 
                       $p->requiresQuestionnaire() && 
                       !$p->questionnaire_completed;
            })
            ->map(function (Person $p) {
                return [
                    'id' => $p->id,
                    'name' => $p->getFullName(),
                    'age' => $p->age,
                ];
            })
            ->values();
        
        return [
            'questionnaire_id' => $questionnaire->id,
            'person_id' => $person->id,
            'person_name' => $person->getFullName(),
            'age' => $person->age,
            'requires_questionnaire' => $person->requiresQuestionnaire(),
            'current_step' => $currentStep->value,
            'current_step_label' => $currentStep->label(),
            'total_steps' => 4,
            'completion_percentage' => $completionPercentage,
            'status' => $questionnaire->status,
            'questions' => $questions,
            'summary' => $summary,
            'navigation' => [
                'can_go_back' => $canGoBack,
                'can_skip_step' => $canSkipStep,
                'next_step_available' => $nextStepAvailable,
                'max_step_reached' => $maxStepReached,
                'previous_step' => $currentStep->previousStep()?->value,
                'next_step' => $currentStep->nextStep()?->value,
            ],
            'warnings' => $warnings,
            'remaining_people' => $remainingPeople,
            'total_remaining_people' => count($remainingPeople),
            'inquiry_summary' => [
                'reference_number' => $inquiry->reference_number,
                'insurance_type' => $inquiry->getInsuranceTypeFormatted(),
                'destination' => $inquiry->getDestinationLabel(),
                'trip_duration' => $inquiry->getInsuranceDurationFormatted(),
            ],
        ];
    }

    /**
     * Get warnings and instructions for current step.
     */
    private function getWarningsForStep(QuestionnaireStep $step): array
    {
        $warnings = [];
        
        switch ($step) {
            case QuestionnaireStep::ELIGIBILITY:
                $warnings = [
                    'Step 1: Eligibility Check',
                    'Any "Yes" answer in this step will make you ineligible for this insurance.',
                    'If unsure about any question, consult your doctor before answering.',
                    'Be honest and accurate in your answers.',
                ];
                break;
                
            case QuestionnaireStep::RATE_C_TRIGGER:
                $warnings = [
                    'Step 2: Rate Category C Triggers',
                    'Any "Yes" answer in this step will automatically place you in Rate Category C (highest rate).',
                    'Rate Category C has significantly higher premiums.',
                    'If you proceed with "Yes" answers, you will skip Step 3.',
                ];
                break;
                
            case QuestionnaireStep::RATE_B_TRIGGER:
                $warnings = [
                    'Step 3: Rate Category B Triggers',
                    'Any "Yes" answer in this step will place you in Rate Category B (medium rate).',
                    'Rate Category B has moderately higher premiums than Category A.',
                    'All "No" answers will keep you in Rate Category A (lowest rate).',
                ];
                break;
                
            case QuestionnaireStep::SMOKING:
                $warnings = [
                    'Step 4: Smoking/Vaping Information',
                    'Smoking or vaping in the last 2 years will add a 10% surcharge to your premium.',
                    'This includes cigarettes, e-cigarettes, and vaping products.',
                    'Honest disclosure is required for accurate premium calculation.',
                ];
                break;
        }
        
        return $warnings;
    }

    /**
     * Get questionnaire status overview for all people in inquiry.
     */
    public function getStatusOverview(string $inquiryId): JsonResponse
    {
        try {
            $inquiry = Inquiry::find($inquiryId);
            if (!$inquiry) {
                return $this->error('Inquiry not found', [], 404);
            }
            
            $peopleStatus = [];
            $completedCount = 0;
            $pendingCount = 0;
            $notRequiredCount = 0;
            
            foreach ($inquiry->people as $person) {
                $requiresQuestionnaire = $person->requiresQuestionnaire();
                $questionnaire = QuestionnaireAnswer::where('person_id', $person->id)->first();
                
                $status = [
                    'person_id' => $person->id,
                    'name' => $person->getFullName(),
                    'age' => $person->age,
                    'requires_questionnaire' => $requiresQuestionnaire,
                ];
                
                if ($requiresQuestionnaire) {
                    if ($questionnaire) {
                        $status['questionnaire_id'] = $questionnaire->id;
                        $status['status'] = $questionnaire->status;
                        $status['status_label'] = $questionnaire->getStatusFormatted();
                        $status['rate_category'] = $questionnaire->rate_category;
                        $status['completion_percentage'] = $questionnaire->getCompletionPercentage();
                        $status['started_at'] = $questionnaire->started_at?->format('Y-m-d H:i:s');
                        $status['completed_at'] = $questionnaire->completed_at?->format('Y-m-d H:i:s');
                        
                        if ($questionnaire->isCompleted()) {
                            $completedCount++;
                        } else {
                            $pendingCount++;
                        }
                    } else {
                        $status['status'] = 'not_started';
                        $status['status_label'] = 'Not Started';
                        $pendingCount++;
                    }
                } else {
                    $status['status'] = 'not_required';
                    $status['status_label'] = 'Not Required';
                    $notRequiredCount++;
                }
                
                $peopleStatus[] = $status;
            }
            
            $overallStatus = 'pending';
            if ($pendingCount === 0 && $completedCount > 0) {
                $overallStatus = 'completed';
            } elseif ($completedCount > 0 && $pendingCount > 0) {
                $overallStatus = 'partial';
            }
            
            return $this->success([
                'overview' => [
                    'total_people' => $inquiry->number_of_people,
                    'requires_questionnaire' => $completedCount + $pendingCount,
                    'completed' => $completedCount,
                    'pending' => $pendingCount,
                    'not_required' => $notRequiredCount,
                    'overall_status' => $overallStatus,
                    'can_proceed_to_payment' => $pendingCount === 0,
                ],
                'people' => $peopleStatus,
            ]);
            
        } catch (Throwable $e) {
            return $this->error($e->getMessage(), [], $e->getCode() ?: 500);
        }
    }
}