<?php

namespace App\Http\Controllers;

use App\Models\Application;
use App\Models\Category;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;

class PublicController extends Controller
{
    protected function shouldIncrementDownload(Request $request, Application $application): bool
    {
        // Avoid counting speculative browser prefetches and repeated retries
        // from the same client as multiple real downloads.
        $purpose = strtolower((string) $request->header('Purpose'));
        $secPurpose = strtolower((string) $request->header('Sec-Purpose'));
        if ($purpose === 'prefetch' || str_contains($secPurpose, 'prefetch')) {
            return false;
        }

        $clientKey = sha1(
            (string) $request->ip() . '|' .
            (string) $request->userAgent() . '|' .
            (string) $application->id
        );

        $cacheKey = 'app_download_counted:' . $clientKey;
        if (Cache::has($cacheKey)) {
            return false;
        }

        Cache::put($cacheKey, true, now()->addHours(24));
        return true;
    }

    protected function missingIconResponse()
    {
        $svg = <<<'SVG'
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 96 96">
  <rect width="96" height="96" rx="18" fill="#EEF2FF"/>
  <rect x="22" y="22" width="52" height="52" rx="12" fill="#C7D2FE"/>
  <path d="M32 62l10-10 8 8 14-14 8 8v8H32z" fill="#6366F1"/>
</svg>
SVG;

        return response($svg, 200)->header('Content-Type', 'image/svg+xml');
    }

    public function home()
    {
        $categories = Category::withCount('applications')->orderBy('name')->get();
        $applications = Application::with(['category', 'files'])
            ->orderByDesc('downloads')
            ->get();

        return view('public.home', [
            'applications' => $applications,
            'categories' => $categories,
            'category' => null
        ]);
    }

    public function category($slug)
    {
        $category = Category::where('slug', $slug)->firstOrFail();
        $categories = Category::withCount('applications')->orderBy('name')->get();

        $applications = Application::where('category_id', $category->id)
            ->with(['category', 'files'])
            ->orderByDesc('downloads')
            ->get();

        return view('public.home', [
            'applications' => $applications,
            'categories' => $categories,
            'category' => $category
        ]);
    }

    public function platform($platform)
    {
        $validPlatforms = ['Android', 'PC', 'iOS', 'macOS'];
        if (!in_array($platform, $validPlatforms)) {
            abort(404);
        }

        $categories = Category::withCount('applications')->orderBy('name')->get();
        $applications = Application::where('platform', $platform)
            ->with('category')
            ->orderByDesc('downloads')
            ->get();

        return view('public.home', compact('applications', 'categories', 'platform'));
    }

    protected function normalizeStoragePath(string $path): string
    {
        $path = trim(str_replace('\\', '/', $path));

        // Handle full URL values saved in older records.
        if (filter_var($path, FILTER_VALIDATE_URL)) {
            $urlPath = parse_url($path, PHP_URL_PATH);
            $path = $urlPath ?: $path;
        }

        // Extract relative path when storage segment appears mid-string.
        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;
    }

    public function appIcon(Application $application)
    {
        try {
            $path = trim($application->icon_path ?? '');
            if (!$path) {
                return $this->missingIconResponse();
            }

            $path = $this->normalizeStoragePath($path);

            // Try Storage disk first
            try {
                if (Storage::disk('public')->exists($path)) {
                    $fullPath = Storage::disk('public')->path($path);
                    $mimeType = mime_content_type($fullPath) ?: 'application/octet-stream';
                    return response()->file($fullPath, ['Content-Type' => $mimeType]);
                }
            } catch (\Exception $e) {
                // Fall back to direct file access
            }

            $publicPath = public_path($path);
            if (file_exists($publicPath)) {
                $mimeType = mime_content_type($publicPath) ?: 'application/octet-stream';
                return response()->file($publicPath, ['Content-Type' => $mimeType]);
            }

            $publicStoragePath = public_path('storage/' . $path);
            if (file_exists($publicStoragePath)) {
                return response()->file($publicStoragePath);
            }

            // Fallback for hosting environments where public/storage symlink is unavailable.
            $storagePath = storage_path('app/public/' . $path);
            if (file_exists($storagePath)) {
                $mimeType = mime_content_type($storagePath) ?: 'application/octet-stream';
                return response()->file($storagePath, ['Content-Type' => $mimeType]);
            }

            return $this->missingIconResponse();
        } catch (\Exception $e) {
            return $this->missingIconResponse();
        }
    }

    /**
     * JSON for in-app updates: matches Application.version and the same /download/{id} URLs as the web store.
     *
     * Query: id (preferred, matches admin URL …/applications/{id}/edit) OR slug, plus platform (default Android).
     * Note: new apps get slug "name-timestamp" (see AdminController), so plain "netbrix" usually will not match.
     */
    public function appUpdate(Request $request)
    {
        $platform = trim((string) $request->query('platform', 'Android'));
        $slug = trim((string) $request->query('slug', ''));
        $idRaw = $request->query('id');

        $application = null;

        if ($idRaw !== null && $idRaw !== '' && ctype_digit((string) $idRaw)) {
            $application = Application::with('files')
                ->where('id', (int) $idRaw)
                ->where('platform', $platform)
                ->first();
        } elseif ($slug !== '') {
            $application = Application::with('files')
                ->where('slug', $slug)
                ->where('platform', $platform)
                ->first();
        } else {
            return response()->json([
                'ok' => false,
                'message' => 'Provide id (application row id) or slug query parameter',
            ], 400);
        }

        if (!$application) {
            return response()->json([
                'ok' => false,
                'message' => 'application not found',
            ], 404);
        }

        $firstFile = $application->files->first();
        $downloadUrl = $firstFile
            ? route('download', ['id' => $application->id, 'file_id' => $firstFile->id], true)
            : route('download', ['id' => $application->id], true);

        return response()->json([
            'ok' => true,
            'version' => $application->version,
            'download_url' => $downloadUrl,
            'release_notes' => $application->description,
            'application_id' => $application->id,
            'slug' => $application->slug,
            'platform' => $application->platform,
        ]);
    }

    public function download(Request $request, $id)
    {
        $application = Application::findOrFail($id);

        $fileId = $request->query('file_id');
        $path = $application->download_url; // Default legacy path

        if ($fileId) {
            $file = $application->files()->find($fileId);
            if ($file) {
                $path = $file->file_path;
            }
        }

        // If path is still empty, try to get the first file from the new system
        if (empty($path) || !Storage::disk('public')->exists(ltrim($path, '/'))) {
            $firstFile = $application->files()->first();
            if ($firstFile) {
                $path = $firstFile->file_path;
            }
        }

        if ($path) {
            $cleanPath = ltrim($path, '/');
            if (Storage::disk('public')->exists($cleanPath)) {
                $fullPath = Storage::disk('public')->path($cleanPath);

                $extension = pathinfo($cleanPath, PATHINFO_EXTENSION);
                // Force .apk if it's an Android app and was saved as .zip or has no extension
                if ($application->platform === 'Android' && ($extension === 'zip' || empty($extension))) {
                    $extension = 'apk';
                }

                if ($this->shouldIncrementDownload($request, $application)) {
                    $application->increment('downloads');
                }

                $downloadName = $application->slug . '-' . time() . '.' . $extension;
                
                // Set proper MIME type headers for downloads
                $headers = [];
                if ($application->platform === 'Android' && $extension === 'apk') {
                    $headers['Content-Type'] = 'application/vnd.android.package-archive';
                } elseif ($application->platform === 'iOS' && $extension === 'ipa') {
                    $headers['Content-Type'] = 'application/octet-stream';
                } elseif ($application->platform === 'macOS' && in_array(strtolower($extension), ['dmg', 'pkg'], true)) {
                    $headers['Content-Type'] = 'application/octet-stream';
                }

                return response()->download($fullPath, $downloadName, $headers);
            }
        }

        return redirect()->route('home')->with('error', 'Download file not found.');
    }
}
