<?php

declare(strict_types=1);

final class PrivateMediaService
{
    public static function root(): string
    {
        return dirname(__DIR__, 2) . '/data/private-media';
    }
    public static function animalDir(int $animalId): string
    {
        return self::root() . '/animals/' . $animalId;
    }
    public static function medicalDir(int $animalId): string
    {
        return self::animalDir($animalId) . '/meds';
    }
    public static function publicDir(int $animalId): string
    {
        return dirname(__DIR__, 2) . '/public/media/animals/' . $animalId;
    }

    public static function ensure(string $dir): void
    {
        if (!is_dir($dir) && !mkdir($dir, 0700, true) && !is_dir($dir)) {
            throw new RuntimeException(t('service.image.directory_failed'));
        }
        @chmod($dir, 0700);
    }

    public static function moveVisibility(int $animalId, string $filename, bool $toPublic): void
    {
        $filename = basename($filename);
        if ($filename === '' || $filename === '.' || $filename === '..') {
            throw new RuntimeException(t('service.private_media.invalid_name'));
        }
        $from = $toPublic ? self::animalDir($animalId) : self::publicDir($animalId);
        $to = $toPublic ? self::publicDir($animalId) : self::animalDir($animalId);
        $source = $from . '/' . $filename;
        $target = $to . '/' . $filename;
        if (!is_file($source)) {
            if (is_file($target)) {
                return;
            }
            throw new RuntimeException(t('service.private_media.not_found'));
        }
        self::ensure($to);
        if (!rename($source, $target)) {
            throw new RuntimeException(t('service.private_media.move_failed'));
        }
        @chmod($target, $toPublic ? 0644 : 0600);
    }

    public static function migrateLegacy(): void
    {
        $db = DB::pdo();
        $private = $db
            ->query('SELECT animal_id,filename FROM animal_photos WHERE is_public=0')
            ->fetchAll(PDO::FETCH_ASSOC);
        foreach ($private as $row) {
            self::moveIfPresent(
                self::publicDir((int) $row['animal_id']) . '/' . basename((string) $row['filename']),
                self::animalDir((int) $row['animal_id']) . '/' . basename((string) $row['filename']),
            );
        }
        $medical = $db->query('SELECT mp.animal_id,mp.filename FROM medical_photos mp')->fetchAll(PDO::FETCH_ASSOC);
        foreach ($medical as $row) {
            self::moveIfPresent(
                self::publicDir((int) $row['animal_id']) . '/meds/' . basename((string) $row['filename']),
                self::medicalDir((int) $row['animal_id']) . '/' . basename((string) $row['filename']),
            );
        }
    }

    private static function moveIfPresent(string $source, string $target): void
    {
        if (!is_file($source) || is_file($target)) {
            return;
        }
        self::ensure(dirname($target));
        if (rename($source, $target)) {
            @chmod($target, 0600);
        }
    }

    public static function send(): void
    {
        $kind = (string) ($_GET['kind'] ?? 'photo');
        $id = (int) ($_GET['id'] ?? 0);
        if ($id <= 0) {
            http_response_code(404);
            return;
        }
        $db = DB::pdo();
        if ($kind === 'medical') {
            if (!PermissionService::can('medical', 'view')) {
                http_response_code(403);
                return;
            }
            $s = $db->prepare(
                'SELECT mp.id,mp.animal_id,mp.filename FROM medical_photos mp JOIN animals a ON a.id=mp.animal_id WHERE mp.id=? AND a.deleted_at IS NULL',
            );
            $s->execute([$id]);
            $row = $s->fetch(PDO::FETCH_ASSOC);
            $path = $row ? self::medicalDir((int) $row['animal_id']) . '/' . basename((string) $row['filename']) : '';
        } else {
            if (!PermissionService::can('animals', 'view')) {
                http_response_code(403);
                return;
            }
            $s = $db->prepare(
                'SELECT ap.id,ap.animal_id,ap.filename,ap.care_round_id FROM animal_photos ap JOIN animals a ON a.id=ap.animal_id WHERE ap.id=? AND ap.is_public=0 AND a.deleted_at IS NULL',
            );
            $s->execute([$id]);
            $row = $s->fetch(PDO::FETCH_ASSOC);
            if ($row && !empty($row['care_round_id']) && !PermissionService::can('medical', 'view')) {
                http_response_code(403);
                return;
            }
            $path = $row ? self::animalDir((int) $row['animal_id']) . '/' . basename((string) $row['filename']) : '';
        }
        if (empty($row) || !is_file($path)) {
            http_response_code(404);
            return;
        }
        $mime = (new finfo(FILEINFO_MIME_TYPE))->file($path) ?: 'application/octet-stream';
        PrivacyService::logAccess(
            'private_' . $kind,
            $id,
            (int) $row['animal_id'],
            basename((string) $row['filename']),
        );
        AuditService::log(
            'private_file_viewed',
            '/private-media',
            'Média privé consulté',
            'animal',
            (int) $row['animal_id'],
            ['kind' => $kind, 'media_id' => $id],
        );
        header('Content-Type: ' . $mime);
        header('Content-Length: ' . filesize($path));
        header('Cache-Control: private,no-store');
        header('X-Content-Type-Options: nosniff');
        readfile($path);
    }
}
