<?php

namespace App\Domain\Files;

use App\Domain\Clinical\Fdi;
use App\Models\Patient;
use App\Models\PatientFile;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;

/**
 * PHI files live on the PRIVATE local disk (storage/app/private) and are
 * streamed through an authorized, tenant-checked controller — never from
 * the public webroot.
 */
class PatientFileService
{
    public const DISK = 'local';
    public const MAX_THUMB = 480; // px, longest edge

    public function store(
        Patient $patient,
        UploadedFile $upload,
        string $type,
        ?array $teeth = null,
        ?string $caption = null,
        ?int $treatmentPlanId = null,
        ?int $appointmentId = null,
        ?int $uploadedBy = null,
    ): PatientFile {
        abort_unless(in_array($type, PatientFile::TYPES, true), 422, __('Unknown file type.'));

        $teeth = $teeth
            ? array_values(array_filter(array_map('intval', $teeth), fn ($t) => Fdi::isValid($t)))
            : null;

        $dir = "tenants/{$patient->tenant_id}/patients/{$patient->id}";
        $path = $upload->store($dir, self::DISK);

        $thumb = null;
        if (str_starts_with((string) $upload->getMimeType(), 'image/')) {
            $thumb = $this->makeThumbnail($path, $dir);
        }

        return PatientFile::create([
            'patient_id' => $patient->id,
            'type' => $type,
            'path' => $path,
            'thumb_path' => $thumb,
            'original_name' => $upload->getClientOriginalName(),
            'mime' => (string) $upload->getMimeType(),
            'size' => $upload->getSize() ?? 0,
            'teeth' => $teeth ?: null,
            'caption' => $caption,
            'treatment_plan_id' => $treatmentPlanId,
            'appointment_id' => $appointmentId,
            'uploaded_by' => $uploadedBy,
        ]);
    }

    /** Pair an AFTER photo with its BEFORE photo (both must belong to the patient). */
    public function pair(PatientFile $before, PatientFile $after): void
    {
        abort_unless(
            $before->patient_id === $after->patient_id
            && $before->type === 'photo_before'
            && $after->type === 'photo_after',
            422,
            __('Pairing requires one Before and one After photo of the same patient.')
        );

        $after->update(['paired_with_id' => $before->id]);
    }

    public function delete(PatientFile $file): void
    {
        Storage::disk(self::DISK)->delete(array_filter([$file->path, $file->thumb_path]));
        $file->after()->update(['paired_with_id' => null]); // unpair dependents
        $file->delete();
    }

    /** GD-based thumbnail — no extra composer packages needed. */
    protected function makeThumbnail(string $path, string $dir): ?string
    {
        $abs = Storage::disk(self::DISK)->path($path);
        $info = @getimagesize($abs);
        if (! $info) {
            return null;
        }

        [$w, $h] = $info;
        $src = match ($info[2]) {
            IMAGETYPE_JPEG => @imagecreatefromjpeg($abs),
            IMAGETYPE_PNG => @imagecreatefrompng($abs),
            IMAGETYPE_WEBP => function_exists('imagecreatefromwebp') ? @imagecreatefromwebp($abs) : null,
            default => null,
        };
        if (! $src) {
            return null;
        }

        $scale = min(1, self::MAX_THUMB / max($w, $h));
        $tw = max(1, (int) round($w * $scale));
        $th = max(1, (int) round($h * $scale));

        $dst = imagecreatetruecolor($tw, $th);
        imagecopyresampled($dst, $src, 0, 0, 0, 0, $tw, $th, $w, $h);

        $thumbPath = $dir.'/thumbs/'.pathinfo($path, PATHINFO_FILENAME).'.jpg';
        Storage::disk(self::DISK)->makeDirectory($dir.'/thumbs');
        imagejpeg($dst, Storage::disk(self::DISK)->path($thumbPath), 82);
        imagedestroy($src);
        imagedestroy($dst);

        return $thumbPath;
    }
}
