<?php

namespace App\Http\Controllers;

use App\Models\ProfessionalPayout;
use App\Services\DisbursementManagementService;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;

class DisbursementManagementController extends Controller
{
    public function __construct(private DisbursementManagementService $service) {}

    public function index(Request $request)
    {
        $filters = $request->validate([
            'professional' => ['nullable', 'string', 'max:120'],
            'date_from' => ['nullable', 'date'],
            'date_to' => ['nullable', 'date', 'after_or_equal:date_from'],
        ]);

        return view('admin.disbursements', $this->service->index($filters));
    }

    public function release(Request $request)
    {
        foreach ($request->file('proofs', []) as $professionalId => $proof) {
            if ($proof instanceof UploadedFile && ! $proof->isValid()) {
                Log::warning('Payout proof upload rejected by PHP.', [
                    'professional_id' => $professionalId,
                    'filename' => $proof->getClientOriginalName(),
                    'upload_error' => $proof->getError(),
                    'upload_error_message' => $proof->getErrorMessage(),
                    'upload_max_filesize' => ini_get('upload_max_filesize'),
                    'post_max_size' => ini_get('post_max_size'),
                ]);

                return back()->withInput()->withErrors(['proofs' => $this->uploadErrorMessage($proof)]);
            }
        }

        $data = $request->validate([
            'bookings' => ['required', 'array', 'min:1'],
            'bookings.*' => ['required', 'integer', 'distinct', 'exists:bookings,id'],
            'proofs' => ['required', 'array', 'min:1'],
            'proofs.*' => ['required', 'file', 'mimes:jpg,jpeg,png,pdf', 'max:10240'],
        ]);

        try {
            $result = $this->service->release($data['bookings'], $request->file('proofs', []));
        } catch (\RuntimeException $exception) {
            return back()->withErrors(['bookings' => $exception->getMessage()]);
        }

        $message = sprintf('Released ₱%s from %d booking(s) in %d DSX invoice(s).', number_format($result['amount'], 2), $result['bookings'], $result['payouts']);
        $message .= $result['email_failures']
            ? ' The payout was recorded, but email delivery failed for: '.implode(', ', $result['email_failures']).'.'
            : ' Payout emails and proof attachments were sent successfully.';

        return redirect()->route('disbursements')->with('success', $message);
    }

    public function invoice(ProfessionalPayout $payout)
    {
        $this->loadDetails($payout);

        return view('admin.payout-invoice', compact('payout'));
    }

    public function show(ProfessionalPayout $payout)
    {
        $this->loadDetails($payout);

        return view('admin.payout-detail', compact('payout'));
    }

    public function downloadInvoice(ProfessionalPayout $payout)
    {
        $this->loadDetails($payout);

        return response(view('emails.payout-invoice-attachment', compact('payout'))->render(), 200, [
            'Content-Type' => 'text/html; charset=UTF-8',
            'Content-Disposition' => 'attachment; filename="'.$payout->reference.'-invoice.html"',
        ]);
    }

    public function proof(ProfessionalPayout $payout)
    {
        abort_unless($payout->proof_path && Storage::disk('payout_proofs')->exists($payout->proof_path), 404);

        return Storage::disk('payout_proofs')->download($payout->proof_path, $payout->proof_original_name ?: basename($payout->proof_path), [
            'Content-Type' => $payout->proof_mime_type ?: 'application/octet-stream',
        ]);
    }

    private function loadDetails(ProfessionalPayout $payout): void
    {
        $payout->load(['professional.user.profile', 'professional.profession', 'bookings.client.profile']);
    }

    private function uploadErrorMessage(UploadedFile $proof): string
    {
        return match ($proof->getError()) {
            UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE => 'The server rejected "'.$proof->getClientOriginalName().'" because its active PHP upload limit is '.ini_get('upload_max_filesize').'.',
            UPLOAD_ERR_PARTIAL => 'The upload of "'.$proof->getClientOriginalName().'" was interrupted.',
            UPLOAD_ERR_NO_TMP_DIR => 'The server PHP temporary directory is missing.',
            UPLOAD_ERR_CANT_WRITE => 'The server could not write the uploaded proof.',
            UPLOAD_ERR_EXTENSION => 'A PHP extension stopped the upload.',
            default => 'The proof could not be uploaded. Please select it again and retry.',
        };
    }
}
