<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;

class Application extends Model
{
    protected $fillable = [
        'category_id',
        'name',
        'slug',
        'description',
        'platform',
        'version',
        'download_url',
        'icon_path',
        'downloads',
    ];

    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    public function files()
    {
        return $this->hasMany(ApplicationFile::class);
    }

    protected function normalizeStoragePath(?string $path): ?string
    {
        if (!$path) {
            return null;
        }

        $path = trim(str_replace('\\', '/', $path));

        // If a full URL is saved, keep only its path component.
        if (filter_var($path, FILTER_VALIDATE_URL)) {
            $urlPath = parse_url($path, PHP_URL_PATH);
            $path = $urlPath ?: $path;
        }

        // Some legacy records may include domain/path before storage folder.
        foreach (['/storage/app/public/', '/storage/', '/public/', '/app/public/'] as $marker) {
            if (str_contains($path, $marker)) {
                $path = substr($path, strpos($path, $marker) + strlen($marker));
                break;
            }
        }

        $path = ltrim($path, '/');

        // Strip all storage prefixes in order of specificity
        if (str_starts_with($path, 'storage/app/public/')) {
            return substr($path, strlen('storage/app/public/'));
        }

        if (str_starts_with($path, 'storage/')) {
            return substr($path, strlen('storage/'));
        }

        if (str_starts_with($path, 'public/')) {
            return substr($path, strlen('public/'));
        }

        if (str_starts_with($path, 'app/public/')) {
            return substr($path, strlen('app/public/'));
        }

        return $path;
    }

    protected function appIconRouteUrl(): string
    {
        // Build URL using the current request base path.
        // This works when app is served from /public on shared hosting.
        if (app()->bound('request')) {
            $baseUrl = rtrim(request()->getBaseUrl(), '/');
            return $baseUrl . '/app-icon/' . $this->id;
        }

        // Safe fallback outside HTTP request context.
        return route('app.icon', $this->id);
    }

    protected function appRootUrl(): string
    {
        // Build root URL without script/base path (avoids accidental /public prefix).
        if (app()->bound('request')) {
            return rtrim(request()->getSchemeAndHttpHost(), '/');
        }

        $appUrl = rtrim((string) config('app.url'), '/');
        if (str_ends_with($appUrl, '/public')) {
            $appUrl = substr($appUrl, 0, -7);
        }

        return $appUrl;
    }

    public function getIconUrlAttribute()
    {
        try {
            $normalizedPath = $this->normalizeStoragePath($this->icon_path);
            if (!$normalizedPath) {
                return null;
            }

            // Production preference: serve from the real uploaded location URL.
            // Example: /storage/app/public/apps/icons/<file>
            $directStoragePath = storage_path('app/public/' . $normalizedPath);
            if (file_exists($directStoragePath)) {
                return $this->appRootUrl() . '/storage/app/public/' . $normalizedPath;
            }

            // If the file exists on the public disk, prefer /storage URL only when
            // public/storage is accessible (symlink or copied directory exists).
            // Otherwise, serve through app.icon route (works on cPanel without terminal).
            try {
                if (Storage::disk('public')->exists($normalizedPath)) {
                    $publicStoragePath = public_path('storage/' . $normalizedPath);
                    if (file_exists($publicStoragePath)) {
                        return Storage::disk('public')->url($normalizedPath);
                    }

                    return $this->appIconRouteUrl();
                }
            } catch (\Exception $e) {
                // Storage not available, try fallback methods
            }

            // Fallback: Check if file exists in public storage directory
            $publicStoragePath = public_path('storage/' . $normalizedPath);
            if (file_exists($publicStoragePath)) {
                return $this->appIconRouteUrl();
            }

            // Fallback: Check if file is directly in public directory
            $publicPath = public_path($normalizedPath);
            if (file_exists($publicPath)) {
                return $this->appIconRouteUrl();
            }

            // Last resort: Use route to serve from controller
            return $this->appIconRouteUrl();
        } catch (\Exception $e) {
            return null;
        }
    }

    public function getDownloadSizeAttribute()
    {
        $path = $this->download_url;

        // Fallback to first architecture file if legacy path is missing or broken
        if (!$path || !Storage::disk('public')->exists(ltrim($path, '/'))) {
            $firstFile = $this->files->first();
            if ($firstFile) {
                $path = $firstFile->file_path;
            }
        }

        if (!$path || !Storage::disk('public')->exists(ltrim($path, '/'))) {
            return null;
        }

        return Storage::disk('public')->size(ltrim($path, '/'));
    }

    public function getDownloadSizeHumanAttribute()
    {
        $bytes = $this->download_size;

        if ($bytes === null) {
            return null;
        }

        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        foreach ($units as $unit) {
            if ($bytes < 1024 || $unit === 'TB') {
                return number_format($bytes, $unit === 'B' ? 0 : 1) . ' ' . $unit;
            }

            $bytes /= 1024;
        }

        return number_format($bytes, 1) . ' TB';
    }
}
