import { ISource, SearchResult, SelectionData, ContentLinks, MediaType } from '../../src/types/source.js';
import { CONFIG } from '../../src/utils/config.js';

export class LoadixSource implements ISource {
    name = 'loadix';
    displayName = 'Loadix';

    private get frontUrl() { return CONFIG.LOADIX_URL || ''; }
    private get baseUrl() { 
        const urlObj = new URL(this.frontUrl);
        return `https://api.${urlObj.host}/api`;
    }
    private tmdbImageBase = 'https://image.tmdb.org/t/p/w500';

    private mapType(type: string): MediaType {
        if (type === 'series') return 'series';
        if (type === 'anime') return 'anime';
        return 'movie';
    }

    private formatSearchResult(hit: any): SearchResult {
        return {
            title: hit.title,
            year: hit.year ? hit.year.toString() : null,
            image: hit.posterPath ? `${this.tmdbImageBase}${hit.posterPath}` : null,
            hrefPath: `${this.frontUrl}/media/${hit.id}`,
            type: this.mapType(hit.type),
            source: this.name
        };
    }

    async search(query: string, mediaType?: MediaType): Promise<SearchResult[]> {
        const url = `${this.baseUrl}/media/search?q=${encodeURIComponent(query)}&page=1&pageSize=30`;
        const res = await fetch(url);
        const data = await res.json();
        
        let hits = data.hits || [];
        if (mediaType && mediaType !== 'other') {
            hits = hits.filter((h: any) => this.mapType(h.type) === mediaType);
        }

        return hits.map((h: any) => this.formatSearchResult(h));
    }

    async getTrending(mediaType: MediaType): Promise<SearchResult[]> {
        const url = `${this.baseUrl}/media/search?q=&page=1&pageSize=30&sort=click_count_desc`;
        const res = await fetch(url);
        const data = await res.json();
        
        let hits = data.hits || [];
        if (mediaType && mediaType !== 'other') {
            hits = hits.filter((h: any) => this.mapType(h.type) === mediaType);
        }

        return hits.map((h: any) => this.formatSearchResult(h));
    }

    async getRecent(): Promise<SearchResult[]> {
        const url = `${this.baseUrl}/media/recent?limit=24`;
        const res = await fetch(url);
        const data = await res.json();
        
        const items = data.items || [];
        return items.map((h: any) => this.formatSearchResult(h));
    }

    async getSelection(identifier: string, type?: string, seasonValue?: string | number): Promise<SelectionData> {
        const idMatch = identifier.match(/media\/([a-f0-9\-]+)/);
        if (!idMatch) throw new Error("URL Loadix invalide.");
        const mediaId = idMatch[1];

        // Fetch links
        const url = `${this.baseUrl}/media/${mediaId}/links?page=1&perPage=100&sort=scope_asc`;
        const res = await fetch(url);
        const data = await res.json();
        const items = data.items || [];

        const links = items.map((item: any) => {
            let episode = null;
            if (item.scope === 'season' && item.seasonNumber) {
                episode = `S${String(item.seasonNumber).padStart(2, '0')}`;
            } else if (item.scope === 'episode' && item.seasonNumber && item.episodeNumber) {
                episode = `S${String(item.seasonNumber).padStart(2, '0')}E${String(item.episodeNumber).padStart(2, '0')}`;
            }

            return {
                id: `${identifier}|${item.id}`,
                host: item.provider || 'unknown',
                quality: item.quality,
                langs: item.language ? [item.language] : [],
                sizeBytes: item.sizeBytes ? parseInt(item.sizeBytes) : undefined,
                size: item.sizeHuman,
                releaseName: item.releaseGroup,
                episode: episode,
                url: null // Protected by Turnstile, resolved later by direct redirect
            };
        });

        // Check if there are any episodes/seasons to determine if it's a series
        const isSeries = links.some((l: any) => l.episode);

        // Extract seasons (just based on found links)
        const seasonsMap = new Map<string, string>();
        if (isSeries) {
            items.forEach((item: any) => {
                if (item.seasonNumber) {
                    const seasonStr = `Saison ${item.seasonNumber}`;
                    seasonsMap.set(String(item.seasonNumber), seasonStr);
                }
            });
        }

        const seasons = Array.from(seasonsMap.entries()).map(([val, label]) => ({
            value: val,
            label: label
        }));

        return {
            links,
            seasons,
            isSeries
        };
    }

    async getContentLinks(identifier: string, season?: number): Promise<ContentLinks> {
        const selection = await this.getSelection(identifier);
        let links = selection.links;

        if (season) {
            const seasonPrefix = `S${String(season).padStart(2, '0')}`;
            links = links.filter(l => l.episode && l.episode.startsWith(seasonPrefix));
        }

        return { links };
    }

    async healthCheck(): Promise<boolean> {
        try {
            const results = await this.getRecent();
            return results.length > 0;
        } catch (e) {
            console.error('[Loadix] Healthcheck failed:', e);
            return false;
        }
    }

    async resolveLink(linkId: string, extraData?: any): Promise<any> {
        const [url] = linkId.split('|');
        // Like Flixart, Turnstile cannot be solved on localhost.
        // We directly return the manual redirection challenge to open Loadix.
        return {
            captcha: 'turnstile',
            url: url
        };
    }
}

// Auto-registration
import { sourceRegistry } from '../../src/core/registry.js';
sourceRegistry.register(new LoadixSource());
