import { computed, inject, Injectable, OnDestroy, signal } from '@angular/core';
import { RuntimeCapabilitiesService } from './runtime-capabilities.service';
import { SettingsStore } from './settings-store.service';

export type DownloadStatus =
    | 'queued'
    | 'downloading'
    | 'completed'
    | 'failed'
    | 'canceled';

export interface DownloadItem {
    id: number;
    playlistId: string;
    xtreamId: number;
    contentType: 'vod' | 'episode';
    seriesXtreamId?: number;
    seasonNumber?: number;
    episodeNumber?: number;
    title: string;
    url: string;
    fileName?: string;
    filePath?: string;
    posterUrl?: string;
    status: DownloadStatus;
    bytesDownloaded?: number;
    totalBytes?: number;
    errorMessage?: string;
    createdAt?: string;
    updatedAt?: string;
}

@Injectable({ providedIn: 'root' })
export class DownloadsService implements OnDestroy {
    private readonly runtime = inject(RuntimeCapabilitiesService);
    private readonly settingsStore = inject(SettingsStore);
    private unsubscribe?: () => void;
    private loadDownloadsRequestId = 0;

    private readonly _isLoadingDownloads = signal(false);
    private readonly _hasLoadedDownloads = signal(false);

    /** Signal for the list of downloads */
    readonly downloads = signal<DownloadItem[]>([]);

    /** Whether the download list is currently being loaded */
    readonly isLoadingDownloads = this._isLoadingDownloads.asReadonly();

    /** Whether the first download list request has completed */
    readonly hasLoadedDownloads = this._hasLoadedDownloads.asReadonly();

    /** Whether the download feature is available (Electron only) */
    readonly isAvailable = computed(() => this.runtime.supportsDownloads);

    /** Whether there are any downloads */
    readonly hasDownloads = computed(() => this.downloads().length > 0);

    /** Active downloads count */
    readonly activeCount = computed(
        () =>
            this.downloads().filter(
                (d) => d.status === 'queued' || d.status === 'downloading'
            ).length
    );

    /** Completed downloads count */
    readonly completedCount = computed(
        () => this.downloads().filter((d) => d.status === 'completed').length
    );

    /** Failed downloads count */
    readonly failedCount = computed(
        () =>
            this.downloads().filter(
                (d) => d.status === 'failed' || d.status === 'canceled'
            ).length
    );

    /** Current download folder */
    readonly downloadFolder = signal<string>('');

    constructor() {
        this.init();
    }

    private async init() {
        if (!this.isAvailable()) {
            return;
        }

        // Load initial download list
        await this.loadDownloads();

        // Load download folder
        await this.loadDownloadFolder();

        // Subscribe to download updates
        this.unsubscribe = window.electron.onDownloadsUpdate(() => {
            this.loadDownloads();
        });
    }

    ngOnDestroy() {
        this.unsubscribe?.();
    }

    /**
     * Load downloads from the backend
     */
    async loadDownloads(playlistId?: string): Promise<void> {
        if (!this.isAvailable()) return;

        const requestId = ++this.loadDownloadsRequestId;
        this._isLoadingDownloads.set(true);

        try {
            const list = await window.electron.downloadsGetList(playlistId);
            if (requestId === this.loadDownloadsRequestId) {
                this.downloads.set(list);
                this._hasLoadedDownloads.set(true);
            }
        } catch (error) {
            console.error('[DownloadsService] Error loading downloads:', error);
            if (requestId === this.loadDownloadsRequestId) {
                this._hasLoadedDownloads.set(true);
            }
        } finally {
            if (requestId === this.loadDownloadsRequestId) {
                this._isLoadingDownloads.set(false);
            }
        }
    }

    /**
     * Load or resolve download folder
     */
    async loadDownloadFolder(): Promise<string> {
        if (!this.isAvailable()) return '';

        // First check settings
        const storedFolder = this.settingsStore.getDownloadFolder?.();
        if (storedFolder) {
            this.downloadFolder.set(storedFolder);
            return storedFolder;
        }

        // Fall back to default
        try {
            const defaultFolder =
                await window.electron.downloadsGetDefaultFolder();
            this.downloadFolder.set(defaultFolder);
            return defaultFolder;
        } catch (error) {
            console.error(
                '[DownloadsService] Error getting default folder:',
                error
            );
            return '';
        }
    }

    /**
     * Start a new download
     */
    async startDownload(data: {
        playlistId: string;
        xtreamId: number;
        contentType: 'vod' | 'episode';
        title: string;
        url: string;
        posterUrl?: string;
        headers?: { userAgent?: string; referer?: string; origin?: string };
        seriesXtreamId?: number;
        seasonNumber?: number;
        episodeNumber?: number;
        // Playlist info for auto-creation if needed (Stalker playlists)
        playlistName?: string;
        playlistType?: 'xtream' | 'stalker' | 'm3u-file' | 'm3u-text' | 'm3u-url';
        serverUrl?: string;
        portalUrl?: string;
        macAddress?: string;
    }): Promise<{ success: boolean; id?: number; error?: string }> {
        if (!this.isAvailable()) {
            return { success: false, error: 'Downloads not available' };
        }

        const folder = await this.loadDownloadFolder();
        if (!folder) {
            return { success: false, error: 'No download folder configured' };
        }

        try {
            const result = await window.electron.downloadsStart({
                ...data,
                downloadFolder: folder,
            });
            return result;
        } catch (error) {
            console.error('[DownloadsService] Error starting download:', error);
            return {
                success: false,
                error: error instanceof Error ? error.message : String(error),
            };
        }
    }

    /**
     * Cancel a download
     */
    async cancelDownload(
        downloadId: number
    ): Promise<{ success: boolean; error?: string }> {
        if (!this.isAvailable()) {
            return { success: false, error: 'Downloads not available' };
        }

        try {
            return await window.electron.downloadsCancel(downloadId);
        } catch (error) {
            console.error(
                '[DownloadsService] Error canceling download:',
                error
            );
            return {
                success: false,
                error: error instanceof Error ? error.message : String(error),
            };
        }
    }

    /**
     * Retry a failed download
     */
    async retryDownload(
        downloadId: number
    ): Promise<{ success: boolean; error?: string }> {
        if (!this.isAvailable()) {
            return { success: false, error: 'Downloads not available' };
        }

        const folder = await this.loadDownloadFolder();
        if (!folder) {
            return { success: false, error: 'No download folder configured' };
        }

        try {
            return await window.electron.downloadsRetry(downloadId, folder);
        } catch (error) {
            console.error(
                '[DownloadsService] Error retrying download:',
                error
            );
            return {
                success: false,
                error: error instanceof Error ? error.message : String(error),
            };
        }
    }

    /**
     * Remove a download from the list
     */
    async removeDownload(
        downloadId: number
    ): Promise<{ success: boolean; error?: string }> {
        if (!this.isAvailable()) {
            return { success: false, error: 'Downloads not available' };
        }

        try {
            return await window.electron.downloadsRemove(downloadId);
        } catch (error) {
            console.error(
                '[DownloadsService] Error removing download:',
                error
            );
            return {
                success: false,
                error: error instanceof Error ? error.message : String(error),
            };
        }
    }

    /**
     * Play a downloaded file
     */
    async playDownload(
        filePath: string
    ): Promise<{ success: boolean; error?: string }> {
        if (!this.isAvailable()) {
            return { success: false, error: 'Downloads not available' };
        }

        try {
            return await window.electron.downloadsPlayFile(filePath);
        } catch (error) {
            console.error('[DownloadsService] Error playing file:', error);
            return {
                success: false,
                error: error instanceof Error ? error.message : String(error),
            };
        }
    }

    /**
     * Reveal file in system file manager
     */
    async revealFile(
        filePath: string
    ): Promise<{ success: boolean; error?: string }> {
        if (!this.isAvailable()) {
            return { success: false, error: 'Downloads not available' };
        }

        try {
            return await window.electron.downloadsRevealFile(filePath);
        } catch (error) {
            console.error('[DownloadsService] Error revealing file:', error);
            return {
                success: false,
                error: error instanceof Error ? error.message : String(error),
            };
        }
    }

    /**
     * Select a new download folder
     */
    async selectFolder(): Promise<string | null> {
        if (!this.isAvailable()) {
            return null;
        }

        try {
            const folder = await window.electron.downloadsSelectFolder();
            if (folder) {
                this.downloadFolder.set(folder);
                // Save to settings
                await this.settingsStore.updateSettings({ downloadFolder: folder });
            }
            return folder;
        } catch (error) {
            console.error(
                '[DownloadsService] Error selecting folder:',
                error
            );
            return null;
        }
    }

    /**
     * Clear completed/failed downloads
     */
    async clearCompleted(
        playlistId?: string
    ): Promise<{ success: boolean }> {
        if (!this.isAvailable()) {
            return { success: false };
        }

        try {
            return await window.electron.downloadsClearCompleted(playlistId);
        } catch (error) {
            console.error(
                '[DownloadsService] Error clearing completed:',
                error
            );
            return { success: false };
        }
    }

    /**
     * Get download progress as percentage
     */
    getProgressPercent(item: DownloadItem): number {
        if (!item.totalBytes || item.totalBytes === 0) {
            return 0;
        }
        return Math.round(
            ((item.bytesDownloaded || 0) / item.totalBytes) * 100
        );
    }

    /**
     * Get download item by xtreamId and playlistId
     */
    getDownloadByContent(
        xtreamId: number,
        playlistId: string,
        contentType: 'vod' | 'episode'
    ): DownloadItem | undefined {
        return this.downloads().find(
            (d) =>
                d.xtreamId === xtreamId &&
                d.playlistId === playlistId &&
                d.contentType === contentType
        );
    }

    /**
     * Check if content is downloaded (completed status)
     */
    isDownloaded(
        xtreamId: number,
        playlistId: string,
        contentType: 'vod' | 'episode'
    ): boolean {
        const download = this.getDownloadByContent(xtreamId, playlistId, contentType);
        return download?.status === 'completed' && !!download.filePath;
    }

    /**
     * Check if content is currently downloading or queued
     */
    isDownloading(
        xtreamId: number,
        playlistId: string,
        contentType: 'vod' | 'episode'
    ): boolean {
        const download = this.getDownloadByContent(xtreamId, playlistId, contentType);
        return download?.status === 'downloading' || download?.status === 'queued';
    }

    /**
     * Get the file path for a downloaded content item
     */
    getDownloadedFilePath(
        xtreamId: number,
        playlistId: string,
        contentType: 'vod' | 'episode'
    ): string | undefined {
        const download = this.getDownloadByContent(xtreamId, playlistId, contentType);
        if (download?.status === 'completed') {
            return download.filePath;
        }
        return undefined;
    }

    /**
     * Format bytes to human readable string
     */
    formatBytes(bytes: number): string {
        if (bytes === 0) return '0 B';
        const k = 1024;
        const sizes = ['B', 'KB', 'MB', 'GB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
    }
}
