<?php

declare(strict_types=1);

namespace App\Application\Campaign\Services;

use App\Application\Campaign\ValueObjects\Campaign;
use App\Framework\Attributes\Singleton;
use App\Framework\OAuth\Providers\SpotifyProvider;
use App\Framework\OAuth\ValueObjects\OAuthToken;

/**
 * Spotify Campaign Integration Service
 *
 * Handles Spotify pre-save functionality for campaigns
 */
#[Singleton]
final readonly class SpotifyCampaignService
{
    public function __construct(
        private SpotifyProvider $spotifyProvider
    ) {
    }

    /**
     * Get Spotify authorization URL for campaign pre-save
     *
     * @param Campaign $campaign
     * @param string $state CSRF state token
     * @return string Authorization URL
     */
    public function getAuthorizationUrl(Campaign $campaign, string $state): string
    {
        return $this->spotifyProvider->getAuthorizationUrl([
            'state' => $state,
            'scope' => [
                'user-library-read',
                'user-library-modify',
                'user-read-email',
            ],
            'show_dialog' => false, // Don't force re-auth if already authorized
        ]);
    }

    /**
     * Add campaign tracks to user's Spotify library
     *
     * @param OAuthToken $token User's OAuth token
     * @param Campaign $campaign Campaign with track data
     * @return bool Success status
     */
    public function addCampaignToLibrary(OAuthToken $token, Campaign $campaign): bool
    {
        if (! $campaign->spotify_enabled || empty($campaign->tracks)) {
            return false;
        }

        // Extract Spotify track IDs from campaign tracks
        $trackIds = array_filter(
            array_map(
                fn ($track) => $this->extractSpotifyId($track['spotify_uri'] ?? null),
                $campaign->tracks
            )
        );

        if (empty($trackIds)) {
            return false;
        }

        return $this->spotifyProvider->addTracksToLibrary($token, $trackIds);
    }

    /**
     * Check if campaign tracks are already in user's library
     *
     * @param OAuthToken $token User's OAuth token
     * @param Campaign $campaign Campaign with track data
     * @return array<string, bool> Track ID => in library status
     */
    public function checkCampaignInLibrary(OAuthToken $token, Campaign $campaign): array
    {
        if (! $campaign->spotify_enabled || empty($campaign->tracks)) {
            return [];
        }

        $trackIds = array_filter(
            array_map(
                fn ($track) => $this->extractSpotifyId($track['spotify_uri'] ?? null),
                $campaign->tracks
            )
        );

        if (empty($trackIds)) {
            return [];
        }

        // Spotify API returns boolean array matching input order
        $results = $this->spotifyProvider->checkTracksInLibrary($token, $trackIds);

        return array_combine($trackIds, $results);
    }

    /**
     * Get user's Spotify profile
     *
     * @param OAuthToken $token User's OAuth token
     * @return array<string, mixed> User profile data
     */
    public function getUserProfile(OAuthToken $token): array
    {
        return $this->spotifyProvider->getUserProfile($token);
    }

    /**
     * Extract Spotify ID from URI
     *
     * Converts spotify:track:xxxx or spotify:album:xxxx to just the ID
     */
    private function extractSpotifyId(?string $uri): ?string
    {
        if ($uri === null) {
            return null;
        }

        // Handle spotify:track:xxxx format
        if (str_starts_with($uri, 'spotify:')) {
            $parts = explode(':', $uri);

            return $parts[2] ?? null;
        }

        // Handle URL format: https://open.spotify.com/track/xxxx
        if (str_contains($uri, 'open.spotify.com')) {
            $parts = explode('/', $uri);

            return end($parts);
        }

        // Already just an ID
        return $uri;
    }
}
