<?php

namespace App\Services\Meet;

use App\Models\FileDownload;
use App\Models\Participant;
use App\Models\Room;
use App\Models\Session;
use App\Models\SessionFile;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class FileSharingService
{
    public function upload(
        Room $room,
        ?Session $session,
        UploadedFile $file,
        string $uploadedByRef,
        string $uploadedByName,
        ?int $expiresInDays = null,
    ): SessionFile {
        $expiresInDays ??= config('meet.files.default_expiry_days');
        $room->loadMissing('organization');

        $bytes = (int) $file->getSize();
        $billing = app(MeetBillingService::class);

        $disk = Storage::disk(config('meet.files.disk', 'local'));
        $path = 'meet-files/'.$room->uuid.'/'.Str::uuid().'_'.$file->getClientOriginalName();
        $disk->put($path, $file->get());

        $sessionFile = SessionFile::create([
            'owner_ref' => $room->owner_ref,
            'room_id' => $room->id,
            'session_id' => $session?->id,
            'uploaded_by_ref' => $uploadedByRef,
            'uploaded_by_name' => $uploadedByName,
            'original_name' => $file->getClientOriginalName(),
            'storage_path' => $path,
            'mime_type' => $file->getMimeType(),
            'file_size' => $bytes,
            'expires_at' => $expiresInDays ? now()->addDays($expiresInDays) : null,
        ]);

        try {
            $billing->chargeFileStorageInitial($sessionFile);
        } catch (\Throwable $e) {
            $disk->delete($path);
            $sessionFile->delete();
            throw $e;
        }

        return $sessionFile;
    }

    public function linkFromDrive(Room $room, string $driveFileId, string $name, string $uploadedByRef, string $uploadedByName): SessionFile
    {
        return SessionFile::create([
            'owner_ref' => $room->owner_ref,
            'room_id' => $room->id,
            'uploaded_by_ref' => $uploadedByRef,
            'uploaded_by_name' => $uploadedByName,
            'original_name' => $name,
            'storage_path' => '',
            'drive_file_id' => $driveFileId,
            'file_size' => 0,
        ]);
    }

    public function download(SessionFile $file, ?Participant $participant = null): string
    {
        abort_if($file->isExpired(), 410, 'File has expired.');
        abort_unless(app(MeetBillingService::class)->storageIsAccessible($file), 402, 'File storage billing is overdue. Top up your Ladill wallet to access this file.');

        FileDownload::create([
            'session_file_id' => $file->id,
            'downloaded_by_ref' => $participant?->user_ref,
            'downloaded_by_name' => $participant?->display_name,
            'ip_address' => request()?->ip(),
            'downloaded_at' => now(),
        ]);

        if ($file->drive_file_id) {
            return $this->driveDownloadUrl($file->drive_file_id);
        }

        return Storage::disk(config('meet.files.disk', 'local'))->path($file->storage_path);
    }

    public function delete(SessionFile $file): void
    {
        if ($file->storage_path) {
            Storage::disk(config('meet.files.disk', 'local'))->delete($file->storage_path);
        }
        $file->delete();
    }

    protected function driveDownloadUrl(string $driveFileId): string
    {
        $base = rtrim((string) config('meet.files.drive_api_url'), '/');
        $key = config('meet.files.drive_api_key');

        if ($base && $key) {
            try {
                $response = Http::withToken($key)->get("{$base}/files/{$driveFileId}/download-url");

                if ($response->successful()) {
                    return $response->json('url', $base.'/files/'.$driveFileId);
                }
            } catch (\Throwable) {
                // fall through
            }
        }

        return $base ? "{$base}/files/{$driveFileId}" : '#';
    }
}
