<?php

namespace Modules\ClinicCore\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\DB;
use Modules\ClinicCore\Entities\ClcAppointment;
use Modules\ClinicCore\Entities\ClcEvaluation;
use Modules\ClinicCore\Entities\ClcEvaluationQuestion;
use Modules\ClinicCore\Entities\ClcEvaluationResponse;

class ClcEvaluationController extends Controller
{
    use \Modules\ClinicCore\Http\Controllers\Traits\LogsClcActivity;

    private function permFor($category)
    {
        return $category === 'clinic'
            ? 'clinic.evaluate_doctor'
            : 'clinic.evaluate_pet_owner';
    }

    /**
     * Render the evaluation form (questions + existing answers if any) for an appointment.
     * Returns HTML fragment for modal body.
     */
    public function form(Request $request, $appointmentId)
    {
        $category = $request->get('category', 'pet_owner');
        if (!auth()->user()->can($this->permFor($category))) {
            abort(403, 'Unauthorized action.');
        }

        $businessId  = $request->session()->get('user.business_id');
        $appointment = ClcAppointment::with(['doctor.user', 'pet', 'owner'])
            ->where('business_id', $businessId)
            ->findOrFail($appointmentId);

        if ($appointment->status !== 'completed') {
            return response()->json([
                'success' => false,
                'msg'     => 'Evaluation is only available after the appointment is marked completed.',
            ], 422);
        }

        $questions = ClcEvaluationQuestion::active()
            ->forBusiness($businessId)
            ->category($category)
            ->orderBy('sort_order')->orderBy('id')
            ->get();

        // Dedupe: hide system defaults when a business-owned override exists with the same text+type
        $businessKeys = $questions->whereNotNull('business_id')->map(function ($q) {
            return strtolower(trim($q->question_text)) . '|' . $q->response_type;
        })->all();
        $questions = $questions->filter(function ($q) use ($businessKeys) {
            if (!is_null($q->business_id)) return true;
            $k = strtolower(trim($q->question_text)) . '|' . $q->response_type;
            return !in_array($k, $businessKeys, true);
        })->values();

        $existing = ClcEvaluation::with('responses')
            ->where('appointment_id', $appointmentId)
            ->where('category', $category)
            ->first();

        $existingByQid = [];
        if ($existing) {
            foreach ($existing->responses as $r) {
                if ($r->question_id) $existingByQid[$r->question_id] = $r;
            }
        }

        $html = view('clinicCore::evaluations.form', compact(
            'appointment', 'category', 'questions', 'existing', 'existingByQid'
        ))->render();

        return response()->json(['success' => true, 'html' => $html]);
    }

    /**
     * Save (upsert) evaluation + responses for an appointment.
     */
    public function store(Request $request, $appointmentId)
    {
        $category = $request->get('category', 'pet_owner');
        if (!auth()->user()->can($this->permFor($category))) {
            abort(403, 'Unauthorized action.');
        }

        $request->validate([
            'category'  => 'required|in:pet_owner,clinic',
            'responses' => 'required|array',
        ]);

        $businessId  = $request->session()->get('user.business_id');
        $appointment = ClcAppointment::where('business_id', $businessId)->findOrFail($appointmentId);

        if ($appointment->status !== 'completed') {
            return response()->json([
                'success' => false,
                'msg'     => 'Evaluation is only available after the appointment is marked completed.',
            ], 422);
        }

        DB::beginTransaction();
        try {
            $evaluation = ClcEvaluation::firstOrNew([
                'appointment_id' => $appointment->id,
                'category'       => $category,
            ]);
            $evaluation->business_id       = $businessId;
            $evaluation->evaluator_user_id = auth()->id();
            $evaluation->doctor_id         = $appointment->doctor_id;
            $evaluation->patient_id            = $appointment->patient_id;
            $evaluation->contact_id        = $appointment->contact_id;
            $evaluation->notes             = $request->input('notes');
            $evaluation->save();

            // Clear existing responses and re-insert (simpler than diffing)
            ClcEvaluationResponse::where('evaluation_id', $evaluation->id)->delete();

            $ratings = [];
            foreach ($request->input('responses', []) as $qid => $data) {
                $question = ClcEvaluationQuestion::find($qid);
                if (!$question) continue;

                $rating  = isset($data['rating']) && $data['rating'] !== '' ? (int) $data['rating'] : null;
                $textAns = isset($data['text']) ? trim((string) $data['text']) : null;
                $yesNo   = isset($data['yes_no']) && $data['yes_no'] !== '' ? (bool) $data['yes_no'] : null;

                if ($question->response_type === 'rating' && $rating !== null) {
                    $ratings[] = max(1, min(5, $rating));
                }

                ClcEvaluationResponse::create([
                    'evaluation_id'          => $evaluation->id,
                    'question_id'            => $question->id,
                    'question_text_snapshot' => $question->question_text,
                    'response_type'          => $question->response_type,
                    'rating'                 => $question->response_type === 'rating' ? $rating : null,
                    'text_answer'            => $question->response_type === 'text' ? $textAns : null,
                    'yes_no_answer'          => $question->response_type === 'yes_no' ? $yesNo : null,
                ]);
            }

            $avg = count($ratings) ? round(array_sum($ratings) / count($ratings), 2) : null;
            $evaluation->avg_rating         = $avg;
            $evaluation->flagged_for_review = $avg !== null && $avg < 3;
            // If was previously reviewed but re-submitted, clear the review state
            if ($evaluation->wasRecentlyCreated === false) {
                $evaluation->reviewed_by   = null;
                $evaluation->reviewed_at   = null;
                $evaluation->review_notes  = null;
            }
            $evaluation->save();

            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            \Log::error('Evaluation save failed: ' . $e->getMessage());
            return response()->json(['success' => false, 'msg' => $e->getMessage()], 500);
        }

        $this->drmLog('evaluate', $evaluation, [
            'after'  => [
                'category'   => $category,
                'avg_rating' => $evaluation->avg_rating,
                'flagged'    => $evaluation->flagged_for_review,
            ],
            'fields' => ['category', 'avg_rating', 'flagged_for_review'],
        ]);

        // Item 3.1 - auto-block check. Only fires for pet_owner ratings;
        // service decides whether settings allow it and whether the
        // cumulative score is below threshold. Returns null if no action.
        $blockResult = null;
        if ($category === 'pet_owner' && $evaluation->contact_id) {
            try {
                $blockResult = app(\Modules\ClinicCore\Services\OwnerBlockService::class)
                    ->evaluateAfterRating(
                        (int) $businessId,
                        (int) $evaluation->contact_id
                    );
            } catch (\Throwable $e) {
                \Log::warning('OwnerBlockService failed: ' . $e->getMessage());
            }
        }

        return response()->json([
            'success'    => true,
            'msg'        => __('clinicCore::lang.saved_successfully'),
            'avg_rating' => $evaluation->avg_rating,
            'flagged'    => $evaluation->flagged_for_review,
            'block'      => $blockResult,
        ]);
    }

    /**
     * Quick status endpoint — returns which evaluations exist for an appointment.
     * Used by the appointment list/show to decide button state.
     */
    public function status($appointmentId)
    {
        $businessId = request()->session()->get('user.business_id');
        $rows = ClcEvaluation::where('business_id', $businessId)
            ->where('appointment_id', $appointmentId)
            ->get(['category', 'avg_rating', 'flagged_for_review', 'reviewed_at']);

        $out = ['pet_owner' => null, 'clinic' => null];
        foreach ($rows as $r) {
            $out[$r->category] = [
                'avg_rating' => $r->avg_rating,
                'flagged'    => (bool) $r->flagged_for_review,
                'reviewed'   => !is_null($r->reviewed_at),
            ];
        }
        return response()->json(['success' => true, 'data' => $out]);
    }

    /**
     * Mark a flagged evaluation as reviewed by management.
     */
    public function review(Request $request, $id)
    {
        if (!auth()->user()->can('clinic.review_evaluations')) {
            abort(403, 'Unauthorized action.');
        }

        $businessId = $request->session()->get('user.business_id');
        $eval = ClcEvaluation::forBusiness($businessId)->findOrFail($id);
        $eval->reviewed_by  = auth()->id();
        $eval->reviewed_at  = now();
        $eval->review_notes = $request->input('review_notes');
        $eval->save();

        $this->drmLog('review', $eval, [
            'after'  => ['reviewed_at' => (string) $eval->reviewed_at, 'review_notes' => $eval->review_notes],
            'fields' => ['reviewed_by', 'reviewed_at', 'review_notes'],
        ]);

        return response()->json(['success' => true, 'msg' => 'Review recorded']);
    }
}
