<?php
/**
 * Flickr URL Parser - extracts photo info from various Flickr URL formats
 * Compatible with PHP 7.2+
 */

class FlickrParser
{
    /**
     * Flickr image size suffixes
     * https://www.flickr.com/services/api/misc.urls.html
     */
    const SIZES = [
        'Square' => '_s',      // 75x75
        'LargeSquare' => '_q', // 150x150
        'Thumbnail' => '_t',   // 100 on longest side
        'Small' => '_m',       // 240 on longest side
        'Small320' => '_n',    // 320 on longest side
        'Medium' => '',        // 500 on longest side
        'Medium640' => '_z',   // 640 on longest side
        'Medium800' => '_c',   // 800 on longest side
        'Large' => '_b',       // 1024 on longest side
        'Large1600' => '_h',   // 1600 on longest side
        'Large2048' => '_k',   // 2048 on longest side
        'Original' => '_o',    // original image
    ];

    /**
     * Parse a Flickr URL and extract photo information
     *
     * @param string $url Flickr URL
     * @return array|null Photo info or null if not a valid Flickr URL
     */
    public function parse($url)
    {
        $url = trim($url);

        // Direct image URL
        if (preg_match('/staticflickr\.com\/\d+\/(\d+)_([a-f0-9]+)(_[a-z])?\.(\w+)/i', $url, $matches)) {
            return [
                'photo_id' => $matches[1],
                'secret' => $matches[2],
                'size_suffix' => isset($matches[3]) ? $matches[3] : '',
                'format' => $matches[4],
                'type' => 'direct',
                'original_url' => $url,
            ];
        }

        // Photo page URL
        if (preg_match('/flickr\.com\/photos\/[^\/]+\/(\d+)/i', $url, $matches)) {
            return [
                'photo_id' => $matches[1],
                'type' => 'page',
                'original_url' => $url,
            ];
        }

        // Short URL (flic.kr)
        if (preg_match('/flic\.kr\/p\/([a-zA-Z0-9]+)/i', $url, $matches)) {
            $photoId = $this->decodeBase58($matches[1]);
            return [
                'photo_id' => $photoId,
                'type' => 'short',
                'original_url' => $url,
            ];
        }

        return null;
    }

    /**
     * Parse multiple URLs (one per line or comma-separated)
     *
     * @param string $input Input text with URLs
     * @return array Array of parsed photo info
     */
    public function parseMultiple($input)
    {
        $results = [];

        // Split by newlines and commas
        $lines = preg_split('/[\r\n,]+/', $input);

        foreach ($lines as $line) {
            $url = trim($line);
            if (empty($url)) continue;

            $parsed = $this->parse($url);
            if ($parsed) {
                $results[] = $parsed;
            }
        }

        return $results;
    }

    /**
     * Build a direct image URL from photo info
     *
     * @param array $photoInfo Photo information
     * @param string $size Size name from SIZES constant
     * @return string Direct image URL
     */
    public function buildImageUrl($photoInfo, $size = 'Large')
    {
        $suffix = isset(self::SIZES[$size]) ? self::SIZES[$size] : self::SIZES['Large'];

        $server = isset($photoInfo['server']) ? $photoInfo['server'] : '65535';
        $photoId = $photoInfo['photo_id'];
        $secret = isset($photoInfo['secret']) ? $photoInfo['secret'] : (isset($photoInfo['originalsecret']) ? $photoInfo['originalsecret'] : '');
        $format = isset($photoInfo['format']) ? $photoInfo['format'] : (isset($photoInfo['originalformat']) ? $photoInfo['originalformat'] : 'jpg');

        // For original size, use originalsecret if available
        if ($size === 'Original' && isset($photoInfo['originalsecret'])) {
            $secret = $photoInfo['originalsecret'];
            $format = isset($photoInfo['originalformat']) ? $photoInfo['originalformat'] : 'jpg';
        }

        return "https://live.staticflickr.com/{$server}/{$photoId}_{$secret}{$suffix}.{$format}";
    }

    /**
     * Decode Flickr's base58 short URL to photo ID
     *
     * @param string $encoded Base58 encoded string
     * @return string Photo ID
     */
    private function decodeBase58($encoded)
    {
        $alphabet = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
        $base = strlen($alphabet);
        $decoded = '0';

        for ($i = 0; $i < strlen($encoded); $i++) {
            $pos = strpos($alphabet, $encoded[$i]);
            $decoded = bcmul($decoded, (string)$base);
            $decoded = bcadd($decoded, (string)$pos);
        }

        return $decoded;
    }

    /**
     * Get available sizes
     *
     * @return array Size names
     */
    public function getAvailableSizes()
    {
        return array_keys(self::SIZES);
    }
}
