<?php

namespace App\Http\Controllers;

use App\Models\FileUpload;
use App\Models\Letter;
use Barryvdh\DomPDF\Facade\Pdf;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;

/**
 * Class LetterController
 *
 * Handles all letter-related operations including CRUD and file attachments.
 * This controller manages student letters with their attachments.
 */
class LetterController extends Controller
{
    /**
     * Display a listing of all letters with their attachments
     *
     * Uses eager loading with 'fileUpload' relation to prevent N+1 query problem
     * Formats each letter response using formatLetterResponse helper
     *
     * @return JsonResponse Array of formatted letters
     */
    public function index(): JsonResponse
    {
        try {
            $letters = Letter::with('fileUpload')
                ->latest() // Sort by latest created_at
                ->get()
                ->map(fn($letter) => $this->formatLetterResponse($letter));

            return response()->json([
                'success' => true,
                'data' => $letters
            ]);
        } catch (Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error fetching letters',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Search letters based on given criteria
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function search(Request $request): JsonResponse
    {
        try {
            $query = Letter::with('fileUpload');

            // Search by NIM
            if ($request->has('nim')) {
                $query->where('nomor_induk_mahasiswa', 'like', '%' . $request->nim . '%');
            }

            $letters = $query
                ->latest() // Always sort by latest
                ->get()
                ->map(fn($letter) => $this->formatLetterResponse($letter));

            return response()->json([
                'success' => true,
                'data' => $letters
            ]);
        } catch (Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error searching letters',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Store a newly created letter
     *
     * Validates input data and handles file upload if present
     * Creates new letter with UUID as primary key
     *
     * @param Request $request Contains letter data and optional file attachment
     * @return JsonResponse Created letter with its file upload info
     */
    public function store(Request $request): JsonResponse
    {
        try {
            // Validate incoming request data
            $validated = $request->validate([
                'nama_mahasiswa' => 'required|string',
                'nomor_induk_mahasiswa' => 'required|string',
                'program_studi_mahasiswa' => 'required|string',
                'tahun_ajaran' => 'required|string',
                'start_date' => 'required|date',
                'completion_date' => 'required|date',
                'nomor_surat_acceptance' => 'nullable|string',
                'nomor_surat_completion' => 'nullable|string',
                'address_to' => 'required|string',
                'letter_scope' => 'required|string',
                'lampiran' => 'nullable|file|mimes:pdf,jpg,png|max:2048',
            ]);

            // Automatically set boolean flags based on letter numbers
            $is_acceptance = !empty($request->nomor_surat_acceptance);
            $is_completion = !empty($request->nomor_surat_completion);

            // Create letter with UUID and modified fields
            $letter = Letter::create([
                'id' => Str::uuid()->toString(),
                ...$validated,
                'is_acceptance' => $is_acceptance,
                'is_completion' => $is_completion,
            ]);

            // Handle file upload if present
            if ($request->hasFile('lampiran')) {
                $this->handleFileUpload($request->file('lampiran'), $letter);
            }

            return response()->json([
                'success' => true,
                'message' => 'Surat berhasil disimpan',
                'data' => $letter->load('fileUpload')
            ], 201);
        } catch (ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors()
            ], 422);
        } catch (Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error creating letter',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Display the specified letter
     *
     * @param string $id Letter UUID
     * @return JsonResponse Letter details with file attachment
     * @throws ModelNotFoundException If letter not found
     */
    public function show(string $id): JsonResponse
    {
        try {
            $letter = Letter::with('fileUpload')->findOrFail($id);
            return response()->json([
                'success' => true,
                'data' => $this->formatLetterResponse($letter)
            ]);
        } catch (ModelNotFoundException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Letter not found'
            ], 404);
        } catch (Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error retrieving letter',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Update the specified letter
     *
     * Handles partial updates with 'sometimes' validation rules
     * Updates file attachment if new file is uploaded
     *
     * @param Request $request Update data and optional new file
     * @param string $id Letter UUID
     * @return JsonResponse Updated letter data
     * @throws ModelNotFoundException If letter not found
     */
    public function update(Request $request, string $id): JsonResponse
    {
        try {
            $letter = Letter::findOrFail($id);

            $validated = $request->validate([
                'nama_mahasiswa' => 'sometimes|string',
                'nomor_induk_mahasiswa' => 'sometimes|string',
                'program_studi_mahasiswa' => 'sometimes|string',
                'tahun_ajaran' => 'sometimes|string',
                'start_date' => 'sometimes|date',
                'completion_date' => 'required|date',
                'is_acceptance' => 'sometimes|boolean',
                'nomor_surat_acceptance' => 'nullable|string',
                'is_completion' => 'nullable|boolean',
                'nomor_surat_completion' => 'nullable|string',
                'address_to' => 'required|string',
                'letter_scope' => 'required|string',
                'lampiran' => 'nullable|file|mimes:pdf,jpg,png|max:2048',
            ]);

            // Force update boolean if nomor_surat_* diberikan
            if ($request->has('nomor_surat_acceptance')) {
                $validated['is_acceptance'] = !empty($request->input('nomor_surat_acceptance'));
            }

            if ($request->has('nomor_surat_completion')) {
                $validated['is_completion'] = !empty($request->input('nomor_surat_completion'));
            }

            // Update letter
            $letter->update($validated);

            // Upload file jika ada
            if ($request->hasFile('lampiran')) {
                $this->handleFileUpload($request->file('lampiran'), $letter, true);
            }

            return response()->json([
                'success' => true,
                'message' => 'Surat berhasil diperbarui',
                'data' => $letter->load('fileUpload')
            ]);
        } catch (ModelNotFoundException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Letter not found'
            ], 404);
        } catch (ValidationException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $e->errors()
            ], 422);
        } catch (Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error updating letter',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Delete letter and its attachment
     * DELETE /api/letters/{id}
     */
    public function destroy(string $id): JsonResponse
    {
        try {
            $letter = Letter::findOrFail($id);
            $this->deleteFileUpload($letter->id);
            $letter->delete();

            return response()->json([
                'success' => true,
                'message' => 'Surat berhasil dihapus'
            ]);
        } catch (ModelNotFoundException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Letter not found'
            ], 404);
        } catch (Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error deleting letter',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Generate signed URL for file attachment
     *
     * Creates temporary signed URL valid for 5 minutes
     * Used for secure file access without exposing actual file path
     *
     * @param string $id FileUpload UUID
     * @return JsonResponse Signed URL and file metadata
     */
    public function letterLampiran(string $id): JsonResponse
    {
        try {
            $file = FileUpload::findOrFail($id);
            $filePath = storage_path('app/public/' . $file->file_path);

            if (!file_exists($filePath)) {
                return response()->json([
                    'success' => false,
                    'message' => 'File not found'
                ], 404);
            }

            // Generate signed URL valid for 5 minutes
            return response()->json([
                'success' => true,
                'data' => [
                    'file_name' => $file->file_name,
                    'mime_type' => $file->mime_type,
                    'url' => URL::signedRoute('file.view', ['id' => $id], now()->addMinutes(5))
                ]
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error retrieving file',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    public function generateSuratAcc($id)
    {
        $letter = Letter::findOrFail($id);
        $letter->start_formatted = Carbon::parse($letter->start_date)->translatedFormat('j F Y');
        $letter->end_formatted = Carbon::parse($letter->completion_date)->translatedFormat('j F Y');
        $pdf = Pdf::loadView('acc_template', ['letter' => $letter, 'tanggalSurat' => Carbon::now()->isoFormat('D MMMM Y')]);
        return $pdf->download('Surat.pdf')
            ->withHeaders([
                'Access-Control-Allow-Origin' => '*',
                'Access-Control-Allow-Methods' => 'GET, OPTIONS',
                'Access-Control-Allow-Headers' => 'Content-Type, Authorization',
            ]);
    }

    public function generateSuratComp($id)
    {
        $letter = Letter::findOrFail($id);
        $letter->start_formatted = Carbon::parse($letter->start_date)->translatedFormat('j F Y');
        $letter->end_formatted = Carbon::parse($letter->completion_date)->translatedFormat('j F Y');
        $pdf = Pdf::loadView('comp_template', ['letter' => $letter, 'tanggalSurat' => Carbon::now()->isoFormat('D MMMM Y')]);
        return $pdf->download('Surat.pdf')
            ->withHeaders([
                'Access-Control-Allow-Origin' => '*',
                'Access-Control-Allow-Methods' => 'GET, OPTIONS',
                'Access-Control-Allow-Headers' => 'Content-Type, Authorization',
            ]);
    }

    /**
     * Format letter data for consistent API response
     *
     * Includes file URL if attachment exists
     * Uses Laravel's asset() helper for public storage URLs
     *
     * @param Letter $letter Letter model instance
     * @return array Formatted letter data
     */
    private function formatLetterResponse(Letter $letter): array
    {
        return [
            'id' => $letter->id,
            'nama_mahasiswa' => $letter->nama_mahasiswa,
            'nomor_induk_mahasiswa' => $letter->nomor_induk_mahasiswa,
            'program_studi_mahasiswa' => $letter->program_studi_mahasiswa,
            'tahun_ajaran' => $letter->tahun_ajaran,
            'start_date' => $letter->start_date,
            'completion_date' => $letter->completion_date,
            'is_acceptance' => $letter->is_acceptance,
            'nomor_surat_acceptance' => $letter->nomor_surat_acceptance,
            'is_completion' => $letter->is_completion,
            'nomor_surat_completion' => $letter->nomor_surat_completion,
            'address_to' => $letter->address_to,
            'letter_scope' => $letter->letter_scope,
            'lampiran' => $letter->fileUpload ? $letter->fileUpload->id : null,
            'created_at' => $letter->created_at,
        ];
    }

    /**
     * Handle file upload process
     *
     * Stores file in public storage
     * Creates FileUpload record
     * Updates letter with file reference
     *
     * @param UploadedFile $file The uploaded file
     * @param Letter $letter Associated letter
     * @param bool $isUpdate Whether this is an update operation
     */
    private function handleFileUpload($file, Letter $letter, bool $isUpdate = false): void
    {
        // Delete existing file if updating
        if ($isUpdate) {
            $this->deleteFileUpload($letter->id);
        }

        // Store file and create record
        $path = $file->store('lampiran', 'public');
        $fileId = Str::uuid()->toString();

        FileUpload::create([
            'id' => $fileId,
            'letter_id' => $letter->id,
            'file_name' => $file->getClientOriginalName(),
            'file_path' => $path,
            'mime_type' => $file->getMimeType(),
        ]);

        $letter->update(['lampiran' => $fileId]);
    }

    /**
     * Helper method to delete file uploads
     */
    private function deleteFileUpload(string $letterId): void
    {
        $file = FileUpload::where('letter_id', $letterId)->first();
        if ($file) {
            Storage::delete($file->file_path);
            $file->delete();
        }
    }
}
