<?php

declare(strict_types=1);

namespace App\Http\Controllers\Legacy;

use App\Http\Controllers\Controller;
use App\Models\Artwork;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Schema;

final class LegacyArtworkPhotoController extends Controller
{
    private const BASE62_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

    private const THUMB_SIZE_MAP = [
        0 => 'xs',
        1 => 'xs',
        2 => 'xs',
        3 => 'sm',
        4 => 'sm',
        5 => 'sm',
        6 => 'md',
    ];

    private static ?bool $hasLegacyIdColumn = null;

    public function __invoke(string $encoded, string $size, string $extension): RedirectResponse
    {
        $artworkId = $this->decodeBase62($encoded);
        $sizeCode = (int) $size;

        abort_if($artworkId === null || $artworkId < 1, 404);

        $artwork = $this->resolveArtwork($artworkId);
        abort_unless($artwork !== null, 404);

        $targetUrl = $sizeCode === 7
            ? $this->resolveOriginalUrl($artwork)
            : $artwork->thumbUrl(self::THUMB_SIZE_MAP[$sizeCode] ?? 'md');

        abort_if(empty($targetUrl), 404);

        return redirect()->away($targetUrl, 301);
    }

    private function decodeBase62(string $value): ?int
    {
        if ($value === '') {
            return null;
        }

        $alphabet = array_flip(str_split(self::BASE62_CHARS));
        $decoded = 0;

        foreach (str_split($value) as $character) {
            if (! array_key_exists($character, $alphabet)) {
                return null;
            }

            $decoded = ($decoded * 62) + $alphabet[$character];
        }

        return $decoded;
    }

    private function resolveArtwork(int $artworkId): ?Artwork
    {
        return Artwork::query()
            ->select(['id', 'hash', 'thumb_ext', 'file_ext', 'file_path', 'is_public', 'is_approved', 'published_at'])
            ->where(function (Builder $query) use ($artworkId): void {
                $query->where('id', $artworkId);

                if ($this->hasLegacyIdColumn()) {
                    $query->orWhere('legacy_id', $artworkId);
                }
            })
            ->where('is_public', true)
            ->where('is_approved', true)
            ->whereNotNull('published_at')
            ->first();
    }

    private function resolveOriginalUrl(Artwork $artwork): ?string
    {
        $cdn = rtrim((string) config('cdn.files_url', 'https://cdn.skinbase.org'), '/');
        $filePath = trim((string) ($artwork->file_path ?? ''), '/');

        if ($filePath !== '') {
            return $cdn . '/' . $filePath;
        }

        $hash = strtolower((string) preg_replace('/[^a-f0-9]/i', '', (string) ($artwork->hash ?? '')));
        $ext = ltrim((string) ($artwork->file_ext ?: $artwork->thumb_ext ?: 'webp'), '.');

        if ($hash === '') {
            return $artwork->thumbUrl('xl') ?? $artwork->thumbUrl('lg') ?? $artwork->thumbUrl('md');
        }

        $prefix = trim((string) config('uploads.object_storage.prefix', 'artworks'), '/');
        $firstDir = substr($hash, 0, 2);
        $secondDir = substr($hash, 2, 2);

        return sprintf('%s/%s/original/%s/%s/%s.%s', $cdn, $prefix, $firstDir, $secondDir, $hash, $ext);
    }

    private function hasLegacyIdColumn(): bool
    {
        if (self::$hasLegacyIdColumn === null) {
            self::$hasLegacyIdColumn = Schema::hasColumn('artworks', 'legacy_id');
        }

        return self::$hasLegacyIdColumn;
    }
}