<?php

namespace App\Services;

use App\Models\SelfPaced\Enrollment;
use App\Models\SelfPaced\PaymentProof;
use Illuminate\Http\UploadedFile;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Storage;

/**
 * PaymentProofService
 *
 * Handles payment proof uploads for cash payments, approval/rejection workflow,
 * and related notifications.
 *
 * Requirements: 17.8, 17.9, 17.10, 17.12, 17.13
 */
class PaymentProofService
{
    const STORAGE_PATH = 'self-paced/payment-proofs';
    const MAX_FILE_SIZE = 5242880; // 5 MB in bytes
    const ALLOWED_MIMES = ['image/jpeg', 'image/png', 'application/pdf'];

    /**
     * Store a payment proof file
     *
     * @param Enrollment $enrollment
     * @param UploadedFile $file
     * @param string $proofType mpesa|bank_slip|institution_receipt
     * @param string $feeType enrollment|certificate|book|resit
     * @param float $amount Amount paid
     * @param string $currency Currency code
     * @return PaymentProof
     * @throws \Exception
     */
    public function storeProof(
        Enrollment $enrollment,
        UploadedFile $file,
        string $proofType,
        string $feeType,
        float $amount,
        string $currency
    ): PaymentProof {
        // Validate file
        if (!in_array($file->getMimeType(), self::ALLOWED_MIMES)) {
            throw new \Exception('Invalid file type. Only JPEG, PNG, and PDF are allowed.');
        }

        if ($file->getSize() > self::MAX_FILE_SIZE) {
            throw new \Exception('File size exceeds 5 MB limit.');
        }

        // Store file
        $storagePath = Storage::disk('public')->putFile(
            self::STORAGE_PATH,
            $file
        );

        if (!$storagePath) {
            throw new \Exception('Failed to store proof file.');
        }

        // Create proof record
        $proof = PaymentProof::create([
            'enrollment_id' => $enrollment->id,
            'user_id' => $enrollment->user_id,
            'course_id' => $enrollment->course_id,
            'fee_type' => $feeType,
            'proof_type' => $proofType,
            'file_path' => $storagePath,
            'file_name' => $file->getClientOriginalName(),
            'file_size' => $file->getSize(),
            'file_mime' => $file->getMimeType(),
            'amount' => $amount,
            'currency' => $currency,
            'status' => 'pending',
        ]);

        return $proof;
    }

    /**
     * Approve a payment proof
     *
     * @param PaymentProof $proof
     * @param int $reviewerId User ID of reviewer
     * @return void
     * @throws \Exception
     */
    public function approveProof(PaymentProof $proof, int $reviewerId): void
    {
        $proof->approve($reviewerId);

        // Dispatch activation based on fee type
        $this->dispatchActivation($proof);

        // Send approval email
        // TODO: Dispatch ApprovalNotification
    }

    /**
     * Reject a payment proof
     *
     * @param PaymentProof $proof
     * @param int $reviewerId User ID of reviewer
     * @param string $reason Rejection reason
     * @return void
     */
    public function rejectProof(PaymentProof $proof, int $reviewerId, string $reason): void
    {
        $proof->reject($reviewerId, $reason);

        // Revert enrollment/fee status to payment_failed
        if ($proof->fee_type === 'enrollment') {
            $proof->enrollment->update([
                'status' => 'payment_failed',
                'registration_fee_paid' => 0,
                'application_fee_paid' => 0,
            ]);
        }

        // Send rejection email
        // TODO: Dispatch RejectionNotification
    }

    /**
     * Get pending proofs with pagination
     *
     * @param int $perPage Results per page
     * @return LengthAwarePaginator
     */
    public function getPendingProofs(int $perPage = 20): LengthAwarePaginator
    {
        return PaymentProof::pending()
            ->with(['enrollment', 'user', 'course'])
            ->orderByDesc('created_at')
            ->paginate($perPage);
    }

    /**
     * Dispatch activation based on proof fee type
     * (Protected method called after approval)
     *
     * @param PaymentProof $proof
     * @return void
     */
    protected function dispatchActivation(PaymentProof $proof): void
    {
        $enrollment = $proof->enrollment;

        switch ($proof->fee_type) {
            case 'enrollment':
                // Activate enrollment
                $enrollment->update([
                    'status' => 'active',
                    'payment_date' => now(),
                    'registration_fee_paid' => $proof->amount,
                    'application_fee_paid' => 0, // Could be split, but defaults to reg fee
                ]);
                // TODO: Send enrollment confirmation email
                break;

            case 'certificate':
                // Mark certificate fee as paid
                $enrollment->update([
                    'certificate_fee_paid' => true,
                ]);
                // TODO: Send certificate payment confirmation email
                break;

            case 'book':
                // Book purchase already handled separately
                break;

            case 'resit':
                // Re-sit fee already handled separately
                break;
        }
    }
}
