import request from "../utils/request";
import {
    Comment,
    CommentRefTypes,
    HtyBaseRoles,
    RefResource,
    RefResourceTypes,
    ResourceNoteGroup,
    ScoreShifan,
    TaskTypes
} from "~/types";
import useLoading from "~/store/loading";
import {showFailToast} from "vant";
import useAi from "~/store/ai";
import {reactive} from "vue";
import {CurrentUserName} from "~/utils";
import cookie from '../utils/cookie';
import usePool from "~/store/pool";
import useRefResource from "~/store/ref-resource";
import useTask from "~/store/task";

const store = reactive<{comments: {[key: string]: Comment[]}}>({
    comments: {}
})


export default function useComment() {

    const {load_start, load_done} = useLoading();
    const {score_comment, get_scores, check_score_status} = useAi()
    const { getKey } = usePool()
    const {createTask} = useTask()
    const {check_resources_task} = useRefResource()

    function refresh(ref_id: string, newly?: any) {
        let cache = store.comments[ref_id] || [];
        if (newly) {
            cache.push(newly)
        }
        // to force re-check and rerender
        store.comments[ref_id] = JSON.parse(JSON.stringify(cache))
    }

    async function update_comment(comment: Comment) {
        load_start()
        let { resource_note_group, ref_resources, ...rest } = comment;
        const {r, e} = await request({url: '/api/v1/ws/update_comment', method: 'POST', data: rest});
        load_done()
        if (!r) {
            showFailToast(e)
        }
    }

    async function prepare_comment(comment: Comment) {
        let { content, ...rest } = comment
        let ref_resources: RefResource[] = [];
        let { audio, photos, video, text } = content;
        if (audio?.tasks?.vals) {
            let task = audio?.tasks?.vals[0]
            if (task && task.task_meta?.media_id) {
                let task_id = await createTask({payload: {media_id: task.task_meta?.media_id}, task_type: TaskTypes.CONVERT_AUDIO_FILE});
                if (task_id) {
                    task.task_id = task_id
                    ref_resources.push(audio as RefResource)
                }

            }
        }
        if (photos?.length) {
            let temp = [];
            for (let i = 0; i < photos.length; i++) {
                let {wx_cache, ...rest} = photos[i];
                // photos uploaded to WX, we need to add combine(compress) task
                if (wx_cache && wx_cache.serverId) {
                    let { serverId } = wx_cache;
                    let task = {
                        task_type: TaskTypes.UPLOAD_PICTURE,
                        payload: {images: [serverId], image_origin: "WX"}
                    }
                    let task_id = await createTask(task);
                    if (task_id) {
                        rest.tasks = {vals: [{task_type: TaskTypes.UPLOAD_PICTURE, task_meta: {media_id: serverId}, task_id}]}
                    }

                }
                temp.push({...rest})
            }
            ref_resources.push(...temp)
        }
        if (video?.resource_url) {
            ref_resources.push(video)
        }
        let meta;
        if (ref_resources.length > 0) {
            meta = "图片/音频/视频信息请进入小程序查看批阅"
        }

        return {...rest, content: {text, meta}, creator_role_key: getKey("current_role"), ref_resources, creator_name: cookie.get(CurrentUserName)} as Comment
    }

    async function create_comment(comment: Comment, shifan?: ScoreShifan) {
        load_start()
        let data = await prepare_comment(comment);
        const {r, d, e} = await request({url: '/api/v1/ws/create_comment', method: 'POST', data});
        load_done()
        if (r) {
            data.id = d.id;
            data.created_at = d.created_at;
            data.created_by = d.created_by;
            // score if comment ref to piyue and contains video
            if (data.creator_role_key === HtyBaseRoles.STUDENT && shifan && [CommentRefTypes.Piyue, CommentRefTypes.ResourceNote].includes(data.ref_type)) {
                await score_comment(data, shifan as ScoreShifan)
                if (data.scores?.length) {
                    // check score after 10s
                    let timer = setTimeout(async () => {
                        let done = await check_score_status(data);
                        if (done) {
                            await refresh(data.ref_id as string)
                        }
                        clearTimeout(timer);
                    }, 5 * 1000)
                }
            }
            refresh(comment.ref_id as string, data)
            check_comments_task(comment.ref_id as string)
            return data;
        }
        showFailToast(e);
    }

    async function load_comments(ref_id: string) {
        load_start();
        const { r, d, e } = await request({url: `/api/v1/ws/get_comments_by_ref_id/${ref_id}`});
        load_done();
        if (r) {
            store.comments[ref_id] = d.sort((a: Comment, b: Comment) => new Date(a.created_at as Date).valueOf() - new Date(b.created_at as Date).valueOf());
        }
    }

    async function get_resource_note_group(refer: {id?: string, resource_note_group?: ResourceNoteGroup}, shifan?: ScoreShifan) {
        const { r, d, e } = await request({url: `/api/v1/ws/get_resource_note_group_by_ref_id/${refer.id}`});
        if (r) {
            refer.resource_note_group = d[0];
            await check_resource_notes_task(d[0], shifan);
        }
    }

    async function get_resource_note_group_by_ref_id(ref_id: string) {
        const { r, d, e } = await request({url: `/api/v1/ws/get_resource_note_group_by_ref_id/${ref_id}`});
        if (r) {
            return d[0];
        }
    }

    async function check_resource_notes_task(resource_note_group?: ResourceNoteGroup, shifan?: ScoreShifan) {
        if (resource_note_group?.resource_notes) {
            for (let k = 0; k < resource_note_group?.resource_notes?.length; k++) {
                let { id, comments } = resource_note_group.resource_notes[k];
                await check_comments_task(id as string, comments, shifan)
            }
        }
    }


    async function check_comments_task(ref_id: string, comments?: Comment[], shifan?: ScoreShifan) {
        if (comments) {
            store.comments[ref_id] = comments;
        }
        comments = store.comments[ref_id];
        if (!comments) return;

        for (let i = 0; i < comments.length; i++) {
            let comment = comments[i];
            let { ref_resources, has_piyue } = comment;
            await check_resources_task(ref_resources);
            if (has_piyue && !comment.resource_note_group) {
                await get_resource_note_group(comment, shifan)
            }
            await check_comment_score(comments[i], shifan)
        }
    }

    async function check_comment_score(comment: Comment, shifan?: ScoreShifan) {

        let { ref_resources, scores, creator_role_key } = comment;
        if (!shifan || creator_role_key !== HtyBaseRoles.STUDENT) return;
        let video = ref_resources?.find(r => r.resource_type === RefResourceTypes.Video);
        if (video && video.resource_url && !scores?.length) {
            // get score info
            let scores = await get_scores(comment.id as string);
            if (scores?.length) {
                let done = await check_score_status(comment);
                if (done) {
                    await refresh(comment.ref_id as string)
                }
                comment.scores = scores;
            }
        }
    }

    async function check_comments_score(ref_id: string, shifan: ScoreShifan) {
        let comments = store.comments[ref_id];
        for(let i = 0; i < comments.length; i++) {
            await check_comment_score(comments[i], shifan)
        }
    }

    function get_comments(ref_id?: string) {
        if (!ref_id) return [];
        return store.comments[ref_id] || []
    }

    function count_comments(ref_id?: string) {
        return get_comments(ref_id).length;
    }

    function get_comment(id: string) {
        for(let k in store.comments) {
            let list = store.comments[k] || [];
            for(let i = 0; i < list.length; i++) {
                if (id === list[i].id) {
                    return list[i];
                }
            }
        }
    }

    return {
        load_comments, create_comment, check_comments_task, check_comments_score, prepare_comment, get_resource_note_group_by_ref_id,
        store, update_comment, get_comments, count_comments, get_comment, get_resource_note_group, check_resource_notes_task
    }
}
