import {queryAll, run, queryOne} from '../../shared/database';
import {getExtension} from '../../shared/extensions';
import * as animeService from '../anime/anime.service';
import * as booksService from '../books/books.service';
import * as aniListService from '../anilist/anilist.service';

interface ListEntryData {
    entry_type: any;
    user_id: number;
    entry_id: number;

    source: string;

    status: string;

    progress: number;
    score: number | null;
}

const USER_DB = 'userdata';

export async function upsertListEntry(entry: any) {
    const {
        user_id,
        entry_id,
        source,
        entry_type,
        status,
        progress,
        score,
        start_date,
        end_date,
        repeat_count,
        notes,
        is_private
    } = entry;

    let prev: any = null;

    try {
        prev = await getSingleListEntry(user_id, entry_id, source, entry_type);
    } catch {
        prev = null;

    }

    const isNew = !prev;
    if (!isNew && prev?.progress != null && progress < prev.progress) {
        return { changes: 0, ignored: true };
    }

    const today = new Date().toISOString().slice(0, 10);

    if (prev?.start_date && !entry.start_date) {
        entry.start_date = prev.start_date;
    }

    if (!prev?.start_date && progress === 1) {
        entry.start_date = today;
    }

    const total =
        prev?.total_episodes ??
        prev?.total_chapters ??
        null;

    if (total && progress >= total) {
        entry.status = 'COMPLETED';
        entry.end_date = today;
    }

    if (source === 'anilist') {
        const token = await getActiveAccessToken(user_id);

        if (token) {
            try {
                const result = await aniListService.updateAniListEntry(token, {
                    mediaId: entry.entry_id,
                    status: entry.status,
                    progress: entry.progress,
                    score: entry.score,
                    start_date: entry.start_date,
                    end_date: entry.end_date,
                    repeat_count: entry.repeat_count,
                    notes: entry.notes,
                    is_private: entry.is_private
                });

                return { changes: 0, external: true, anilistResult: result };
            } catch (err) {
                console.error("Error actualizando AniList:", err);
            }
        }
    }

    const sql = `
        INSERT INTO ListEntry
        (
            user_id, entry_id, source, entry_type, status,
            progress, score,
            start_date, end_date, repeat_count, notes, is_private,
            updated_at
        )
        VALUES
            (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
            ON CONFLICT(user_id, entry_id) DO UPDATE SET
            source = EXCLUDED.source,
                                                  entry_type = EXCLUDED.entry_type,
                                                  status = EXCLUDED.status,
                                                  progress = EXCLUDED.progress,
                                                  score = EXCLUDED.score,
                                                  start_date = EXCLUDED.start_date,
                                                  end_date = EXCLUDED.end_date,
                                                  repeat_count = EXCLUDED.repeat_count,
                                                  notes = EXCLUDED.notes,
                                                  is_private = EXCLUDED.is_private,
                                                  updated_at = CURRENT_TIMESTAMP;
    `;

    const params = [
        entry.user_id,
        entry.entry_id,
        entry.source,
        entry.entry_type,
        entry.status,
        entry.progress,
        entry.score ?? null,
        entry.start_date || null,
        entry.end_date || null,
        entry.repeat_count ?? 0,
        entry.notes || null,
        entry.is_private ?? 0
    ];

    try {
        const result = await run(sql, params, USER_DB);
        return { changes: result.changes, lastID: result.lastID, external: false };
    } catch (error) {
        console.error("Error al guardar la entrada de lista:", error);
        throw new Error("Error en la base de datos al guardar la entrada.");
    }
}

export async function getUserList(userId: number): Promise<any> {
    const sql = `
        SELECT * FROM ListEntry
        WHERE user_id = ?
        ORDER BY updated_at DESC;
    `;

    try {
        const dbList = await queryAll(sql, [userId], USER_DB) as ListEntryData[];
        const connected = await isConnected(userId);

        let finalList: any[] = [...dbList];

        if (connected) {
            const anilistEntries = await aniListService.getUserAniList(userId);
            const localWithoutAnilist = dbList.filter(
                entry => entry.source !== 'anilist'
            );

            finalList = [...anilistEntries, ...localWithoutAnilist];
        }

        const enrichedListPromises = finalList.map(async (entry) => {
            if (entry.source === 'anilist' && connected) {
                let finalTitle = entry.title;
                if (typeof finalTitle === 'object' && finalTitle !== null) {
                    finalTitle =
                        finalTitle.userPreferred ||
                        finalTitle.english ||
                        finalTitle.romaji ||
                        'Unknown Title';
                }

                return {
                    ...entry,
                    title: finalTitle,
                    poster: entry.poster || 'https://placehold.co/400x600?text=No+Cover',
                };
            }

            let contentDetails: any | null = null;
            const id = entry.entry_id;
            const type = entry.entry_type;
            const ext = getExtension(entry.source);

            try {
                if (type === 'ANIME') {
                    if(entry.source === 'anilist') {
                        const anime: any = await animeService.getAnimeById(id);
                        contentDetails = {
                            title: anime?.title.english || 'Unknown Anime Title',
                            poster: anime?.coverImage?.extraLarge || '',
                            total_episodes: anime?.episodes || 0,
                        };
                    }
                    else{
                        const anime: any = await animeService.getAnimeInfoExtension(ext, id.toString());

                        contentDetails = {
                            title: anime?.title || 'Unknown Anime Title',
                            poster: anime?.image || 'https://placehold.co/400x600?text=No+Cover',
                            total_episodes: anime?.episodes || 0,
                        };
                    }

                } else if (type === 'MANGA' || type === 'NOVEL') {
                    if(entry.source === 'anilist') {
                        const book: any  = await booksService.getBookById(id);

                        contentDetails = {
                            title: book?.title.english || 'Unknown Book Title',
                            poster: book?.coverImage?.extraLarge || 'https://placehold.co/400x600?text=No+Cover',
                            total_chapters: book?.chapters || book?.volumes * 10 || 0,
                        };
                    }
                    else{
                        const book: any  = await booksService.getBookInfoExtension(ext, id.toString());

                        contentDetails = {
                            title: book?.title || 'Unknown Book Title',
                            poster: book?.image || '',
                            total_chapters: book?.chapters || book?.volumes * 10 || 0,
                        };
                    }
                }

            } catch {
                contentDetails = {
                    title: 'Error Loading Details',
                    poster: 'https://placehold.co/400x600?text=No+Cover',
                };
            }

            let finalTitle = contentDetails?.title || 'Unknown Title';
            let finalPoster = contentDetails?.poster || 'https://placehold.co/400x600?text=No+Cover';

            if (typeof finalTitle === 'object' && finalTitle !== null) {
                finalTitle =
                    finalTitle.userPreferred ||
                    finalTitle.english ||
                    finalTitle.romaji ||
                    'Unknown Title';
            }

            return {
                ...entry,
                title: finalTitle,
                poster: finalPoster,
                total_episodes: contentDetails?.total_episodes,
                total_chapters: contentDetails?.total_chapters,
            };
        });

        return await Promise.all(enrichedListPromises);

    } catch (error) {
        console.error("Error al obtener la lista del usuario:", error);
        throw new Error("Error getting list.");
    }
}

export async function deleteListEntry(
    userId: number,
    entryId: string | number,
    source: string
) {

    if (source === 'anilist') {
        const token = await getActiveAccessToken(userId);

        if (token) {
            try {
                await aniListService.deleteAniListEntry(
                    token,
                    Number(entryId),
                );

                return { success: true, external: true };
            } catch (err) {
                console.error("Error borrando en AniList:", err);
            }
        }
    }

    const sql = `
        DELETE FROM ListEntry
        WHERE user_id = ? AND entry_id = ?;
    `;

    const result = await run(sql, [userId, entryId], USER_DB);
    return { success: result.changes > 0, changes: result.changes, external: false };
}

export async function getSingleListEntry(
    userId: number,
    entryId: string | number,
    source: string,
    entryType: string
): Promise<any> {

    const localSql = `
        SELECT * FROM ListEntry
        WHERE user_id = ? AND entry_id = ? AND source = ? AND entry_type = ?;
    `;

    const localResult = await queryAll(
        localSql,
        [userId, entryId, source, entryType],
        USER_DB
    ) as any[];

    if (localResult.length > 0) {
        const entry = localResult[0];

        const contentDetails: any =
            entryType === 'ANIME'
                ? await animeService.getAnimeById(entryId).catch(() => null)
                : await booksService.getBookById(entryId).catch(() => null);

        let finalTitle = contentDetails?.title || 'Unknown';
        let finalPoster = contentDetails?.coverImage?.extraLarge ||
            contentDetails?.image ||
            'https://placehold.co/400x600?text=No+Cover';

        if (typeof finalTitle === 'object') {
            finalTitle =
                finalTitle.userPreferred ||
                finalTitle.english ||
                finalTitle.romaji ||
                'Unknown';
        }

        return {
            ...entry,
            title: finalTitle,
            poster: finalPoster,
            total_episodes: contentDetails?.episodes,
            total_chapters: contentDetails?.chapters,
        };
    }

    if (source === 'anilist') {

        const connected = await isConnected(userId);
        if (!connected) return null;

        const sql = `
            SELECT access_token
            FROM UserIntegration
            WHERE user_id = ? AND platform = 'AniList';
        `;

        const integration = await queryOne(sql, [userId], USER_DB) as any;
        if (!integration?.access_token) return null;
        if (entryType === 'NOVEL') {entryType = 'MANGA'}

        const aniEntry = await aniListService.getSingleAniListEntry(
            integration.access_token,
            Number(entryId),
            entryType as any
        );

        if (!aniEntry) return null;

        const contentDetails: any =
            entryType === 'ANIME'
                ? await animeService.getAnimeById(entryId).catch(() => null)
                : await booksService.getBookById(entryId).catch(() => null);

        let finalTitle = contentDetails?.title || 'Unknown';
        let finalPoster = contentDetails?.coverImage?.extraLarge ||
            contentDetails?.image ||
            'https://placehold.co/400x600?text=No+Cover';

        if (typeof finalTitle === 'object') {
            finalTitle =
                finalTitle.userPreferred ||
                finalTitle.english ||
                finalTitle.romaji ||
                'Unknown';
        }

        return {
            user_id: userId,
            ...aniEntry,
            title: finalTitle,
            poster: finalPoster,
            total_episodes: contentDetails?.episodes,
            total_chapters: contentDetails?.chapters,
        };
    }

    return null;
}

export async function getActiveAccessToken(userId: number): Promise<string | null> {
    const sql = `
        SELECT access_token, expires_at
        FROM UserIntegration
        WHERE user_id = ? AND platform = 'AniList';
    `;

    try {
        const integration = await queryOne(sql, [userId], USER_DB) as any | null;

        if (!integration) {
            return null;

        }

        const expiryDate = new Date(integration.expires_at);
        const now = new Date();

        const fiveMinutes = 5 * 60 * 1000;

        if (expiryDate.getTime() < (now.getTime() + fiveMinutes)) {

            console.log(`AniList token for user ${userId} expired or near expiry.`);
            return null;
        }

        return integration.access_token;

    } catch (error) {
        console.error("Error al verificar la integración de AniList:", error);
        return null;
    }
}

export async function isConnected(userId: number): Promise<boolean> {
    const token = await getActiveAccessToken(userId);
    return !!token;
}

export async function getUserListByFilter(
    userId: number,
    status?: string,
    entryType?: string
): Promise<any> {

    let sql = `
        SELECT * FROM ListEntry
        WHERE user_id = ?
        ORDER BY updated_at DESC;
    `;

    const params: any[] = [userId];

    try {
        const dbList = await queryAll(sql, params, USER_DB) as ListEntryData[];
        const connected = await isConnected(userId);

        const statusMap: any = {
            watching: 'CURRENT',
            reading: 'CURRENT',
            completed: 'COMPLETED',
            paused: 'PAUSED',
            dropped: 'DROPPED',
            planning: 'PLANNING'
        };

        const mappedStatus = status ? statusMap[status.toLowerCase()] : null;

        let finalList: any[] = [];

        const filteredLocal = dbList.filter((entry) => {
            if (mappedStatus && entry.status !== mappedStatus) return false;

            if (entryType) {
                if (entryType === 'MANGA') {

                    if (!['MANGA', 'NOVEL'].includes(entry.entry_type)) return false;
                } else {
                    if (entry.entry_type !== entryType) return false;
                }
            }

            return true;
        });

        let filteredAniList: any[] = [];

        if (connected) {
            const anilistEntries = await aniListService.getUserAniList(userId);

            filteredAniList = anilistEntries.filter((entry: any) => {
                if (mappedStatus && entry.status !== mappedStatus) return false;

                if (entryType) {
                    if (entryType === 'MANGA') {
                        if (!['MANGA', 'NOVEL'].includes(entry.entry_type)) return false;
                    } else {
                        if (entry.entry_type !== entryType) return false;
                    }
                }

                return true;
            });
        }

        finalList = [...filteredAniList, ...filteredLocal];

        const enrichedListPromises = finalList.map(async (entry) => {

            if (entry.source === 'anilist') {
                let finalTitle = entry.title;

                if (typeof finalTitle === 'object' && finalTitle !== null) {
                    finalTitle =
                        finalTitle.userPreferred ||
                        finalTitle.english ||
                        finalTitle.romaji ||
                        'Unknown Title';
                }

                return {
                    ...entry,
                    title: finalTitle,
                    poster: entry.poster || 'https://placehold.co/400x600?text=No+Cover',
                };
            }

            let contentDetails: any | null = null;
            const id = entry.entry_id;
            const type = entry.entry_type;
            const ext = getExtension(entry.source);

            try {
                if (type === 'ANIME') {
                    const anime: any = await animeService.getAnimeInfoExtension(ext, id.toString());

                    contentDetails = {
                        title: anime?.title || 'Unknown Anime Title',
                        poster: anime?.image || '',
                        total_episodes: anime?.episodes || 0,
                    };

                } else if (type === 'MANGA' || type === 'NOVEL') {
                    const book: any = await booksService.getBookInfoExtension(ext, id.toString());

                    contentDetails = {
                        title: book?.title || 'Unknown Book Title',
                        poster: book?.image || '',
                        total_chapters: book?.chapters || book?.volumes * 10 || 0,
                    };
                }

            } catch {
                contentDetails = {
                    title: 'Error Loading Details',
                    poster: 'https://placehold.co/400x600?text=No+Cover',
                };
            }

            let finalTitle = contentDetails?.title || 'Unknown Title';
            let finalPoster = contentDetails?.poster || 'https://placehold.co/400x600?text=No+Cover';

            if (typeof finalTitle === 'object' && finalTitle !== null) {
                finalTitle =
                    finalTitle.userPreferred ||
                    finalTitle.english ||
                    finalTitle.romaji ||
                    'Unknown Title';
            }

            return {
                ...entry,
                title: finalTitle,
                poster: finalPoster,
                total_episodes: contentDetails?.total_episodes,
                total_chapters: contentDetails?.total_chapters,
            };
        });

        return await Promise.all(enrichedListPromises);

    } catch (error) {
        console.error("Error al filtrar la lista del usuario:", error);
        throw new Error("Error en la base de datos al obtener la lista filtrada.");
    }
}