import React, { useEffect } from "react";
import { Searchbar, Title } from 'react-native-paper';
import { ScrollView, ActivityIndicator, StyleSheet, SafeAreaView, View } from 'react-native';
import { useIsFocused } from "@react-navigation/native";
import API from "../API";
import CourseCard from "../components/CourseCard";
import { useSnapshot } from 'valtio';
import GlobalState from '../contexts/GlobalState.js';
import i18n from "../i18nMessages.js";
import AsyncStorage from '@react-native-async-storage/async-storage';

const COURSES_LOG_PREFIX = '[Courses]';
const logCourses = (...args) => {
    if (__DEV__) console.log(COURSES_LOG_PREFIX, ...args);
};

const emptyCoursesData = {
    courses: [],
    popular: [],
    watching: [],
};

const getCourses = async (profileObj = {}) => {
    let courses = [];
    let popular = [];
    logCourses('getCourses:start', {
        viewerId: profileObj?._id || null,
        hasViewerData: !!profileObj?.data,
    });
    await API.getCourses().then((data) => {
        const groups = Array.isArray(data?.groups) ? data.groups : [];
        courses = groups;
        popular = [...groups].sort((a, b) => {
            return Object.keys(b.subscribed).length - Object.keys(a.subscribed).length;
        });
        logCourses('getCourses:groups', {
            groups: groups.length,
            popular: popular.length,
        });
    });
    let watching = {};
    let watchingProms = [];
    let watchingStats = {
        rawEntries: 0,
        explicitProfileId: 0,
        fallbackByPost: 0,
        skippedNoProgress: 0,
        skippedNoProfileId: 0,
        courseProfilesResolved: 0,
    };
    const pushWatchingProgress = (profile, progress, profileId) => {
        if (!profile?.isCourse) return;
        if (!watching[profileId]) {
            watching[profileId] = { profile, progress: [], mostRecent: 0 };
        }
        if (watching[profileId].mostRecent < (progress?.ts || 0)) {
            watching[profileId].mostRecent = progress.ts || 0;
        }
        watching[profileId].progress.push(progress);
        watchingStats.courseProfilesResolved += 1;
    };
    let viewerData = {};
    try {
        // Detach potential proxy/non-extensible objects before iterating keys.
        viewerData = JSON.parse(JSON.stringify(profileObj?.data || {}));
    } catch (error) {
        viewerData = {};
    }
    const viewerKeys = Object.keys(viewerData);
    logCourses('watching:viewerData', {
        entries: viewerKeys.length,
        sampleKeys: viewerKeys.slice(0, 5),
    });
    Object.keys(viewerData).forEach((videoId) => {
        watchingStats.rawEntries += 1;
        const progress = viewerData[videoId];
        if (!progress) {
            watchingStats.skippedNoProgress += 1;
            return;
        }

        const explicitProfileId = progress.profileId || progress.profileid;
        if (explicitProfileId) {
            watchingStats.explicitProfileId += 1;
            watchingProms.push(API.getUserProfile(explicitProfileId).then((profile) => {
                pushWatchingProgress(profile, progress, explicitProfileId);
            }));
            return;
        }

        // Backward compatibility: old progress entries may not include profileId.
        const postId = progress.postId || videoId;
        if (!postId) {
            watchingStats.skippedNoProfileId += 1;
            return;
        }
        watchingStats.fallbackByPost += 1;
        watchingProms.push(
            API.getPost(postId).then((post) => {
                const fallbackProfileId = post?.profileid;
                if (!fallbackProfileId) return 0;
                return API.getUserProfile(fallbackProfileId).then((profile) => {
                    pushWatchingProgress(profile, progress, fallbackProfileId);
                });
            })
        );
    });
    let watchingArray = [];
    await Promise.all(watchingProms).then(() => {
        for (const courseId in watching) {
            watchingArray.push(watching[courseId]);
        }
        watchingArray = watchingArray.sort((a, b) => {
            return b.mostRecent - a.mostRecent;
        });
    });
    logCourses('watching:resolved', {
        ...watchingStats,
        uniqueCourses: watchingArray.length,
    });
    return {
        courses: courses.slice(0, 10),
        popular: popular.slice(0, 10),
        watching: watchingArray.slice(0, 10),
    }
}

const storeCoursesCache = async (value) => {
    try {
        const jsonValue = JSON.stringify(value)
        await AsyncStorage.setItem('courses', jsonValue)
    } catch (e) {
    }
}

const getCoursesCache = async () => {
    try {
        const value = await AsyncStorage.getItem('courses')
        if (value !== null) {
            return JSON.parse(value);
        }
        return emptyCoursesData;
    } catch (e) {
        return emptyCoursesData;
    }
}

const Courses = () => {
    const gState = useSnapshot(GlobalState);
    const viewer = gState.me;
    const isFocused = useIsFocused();
    const [searchQuery, setSearchQuery] = React.useState('');
    const [groups, setGroups] = React.useState([]);
    const [popular, setPopular] = React.useState([]);
    const [watching, setWatching] = React.useState([]);
    const [queryTimer, setQueryTimer] = React.useState(0);

    useEffect(() => {
        if (!isFocused) return;
        let subscribed = true;
        const getData = async () => {
            const cached = await getCoursesCache();
            logCourses('cache:read', {
                courses: Array.isArray(cached?.courses) ? cached.courses.length : 0,
                popular: Array.isArray(cached?.popular) ? cached.popular.length : 0,
                watching: Array.isArray(cached?.watching) ? cached.watching.length : 0,
            });
            if (subscribed) {
                setGroups(Array.isArray(cached?.courses) ? cached.courses : []);
                setPopular(Array.isArray(cached?.popular) ? cached.popular : []);
                setWatching(Array.isArray(cached?.watching) ? cached.watching : []);
            }
            let r = await getCourses(viewer);
            logCourses('live:resolved', {
                courses: Array.isArray(r?.courses) ? r.courses.length : 0,
                popular: Array.isArray(r?.popular) ? r.popular.length : 0,
                watching: Array.isArray(r?.watching) ? r.watching.length : 0,
            });
            if(subscribed){
                setGroups(r.courses || []);
                setPopular(r.popular || []);
                setWatching(r.watching || []);
            }
            storeCoursesCache(r);
        };
        getData();
        return () => {
            subscribed = false;
        }
    }, [isFocused, viewer?._id])

    const onChangeSearch = query => {
        setSearchQuery(query);
        if (queryTimer) clearTimeout(queryTimer);
        let timerId = setTimeout(() => {
            if (!query) {
                return API.getCourses('').then((data) => {
                    setGroups(data.groups || []);
                });
            }
            API.searchCourses(query).then((data) => {
                setGroups(data.groups || []);
            })

        }, 300);
        setQueryTimer(timerId);
    };
    const renderCourseCards = (items = [], twoCols = false) => {
        return items.map((item, index) => (
            <CourseCard
                key={item?._id || item?.profile?._id || `course-${index}`}
                profileObj={item}
                twoCols={twoCols}
            />
        ));
    };
    const renderWatchingCards = (items = []) => {
        return items.map((item, index) => (
            <CourseCard
                key={item?.profile?._id || item?._id || `watching-${index}`}
                profileObj={item?.profile}
            />
        ));
    };

    useEffect(() => {
        logCourses('render', {
            searchQueryLength: searchQuery.length,
            groups: groups.length,
            popular: popular.length,
            watching: watching.length,
            showWatching: searchQuery.length === 0 && watching.length > 0,
        });
    }, [searchQuery, groups.length, popular.length, watching.length]);

    return (
        <SafeAreaView style={styles.container}>
            <Searchbar
                placeholder = {i18n.t("message.searchCourses")}
                onChangeText={onChangeSearch}
                value={searchQuery}
            />
            {groups.length ? <></> : <ActivityIndicator />}
            <ScrollView>
                {
                    (searchQuery.length === 0 &&  watching.length) ?
                    <View>
                        <Title style={styles.title} >{i18n.t("message.continueWatching")}:</Title>
                        <ScrollView horizontal={true} showsHorizontalScrollIndicator={false}>
                            {renderWatchingCards(watching)}
                        </ScrollView>
                    </View> : <></>
                }
                {
                    (searchQuery.length === 0 &&  groups.length) ?
                    <>
                        <Title style={styles.title} >{i18n.t("message.recentlyAdded")}:</Title>
                        <ScrollView horizontal={true} showsHorizontalScrollIndicator={false}>
                            {renderCourseCards(groups)}
                        </ScrollView>
                    </> : <></>
                }
                {
                    (searchQuery.length === 0 &&  popular.length) ?
                    <>
                        <Title style={styles.title} >{i18n.t("message.popularCourses")}:</Title>
                        <ScrollView horizontal={true} showsHorizontalScrollIndicator={false}>
                            {renderCourseCards(popular)}
                        </ScrollView>
                    </> : <></>
                }
                {
                    (searchQuery.length !== 0 &&  groups.length) ?
                    <View style={styles.searchGrid}>
                        {renderCourseCards(groups, true)}
                    </View> : <></>
                }
            </ScrollView>
        </SafeAreaView>
    )
}

export default Courses;

const styles = StyleSheet.create({
    container: {
        flex: 1
    },
    title: {
        padding: 10,
        fontSize: 30,
        marginTop: 15,
        fontWeight: "bold",
        color: "#777"
    },
    searchGrid: {
        flexDirection: 'row',
        flexWrap: 'wrap',
        justifyContent: 'space-between',
        paddingHorizontal: 4,
    }
});
