<script setup lang="ts">
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import { useRoute, useRouter, onBeforeRouteLeave } from 'vue-router'
import { Card, Typography, Button, Spin, Tag, List, message } from 'ant-design-vue'
import { apiClient, API } from '../router/api'
import type { ProgressSessionApi, FlowLookup } from '../types/onboarding'
import { Marked } from 'marked'
import DOMPurify from 'dompurify'

const route = useRoute()
const router = useRouter()
const roleId = computed(() => route.params.roleId as string)
const selectedUserUuid = computed(() => String(route.query.user_uuid || ''))
const selectedFlowUuid = computed(() => String(route.query.flow_uuid || ''))

const loading = ref(false)
const monitoring = ref(false)
const roleName = ref('Unknown Role')
const learnerName = ref('Learner')
const flowTitle = ref('')
const sessions = ref<ProgressSessionApi[]>([])
const feedback = ref<string>('')
const monitorLogs = ref<string[]>([])
const monitorSocket = ref<WebSocket | null>(null)
const monitorTimeout = ref<number | null>(null)

const marked = new Marked()

const latestSession = computed(() => sessions.value[0] || null)
const latestSessionCompleted = computed(() => latestSession.value?.status === 'completed')
const renderedFeedback = computed(() => {
    const raw = String(feedback.value || '').trim()
    if (!raw) {
        return '<p>No feedback yet.</p>'
    }
    return DOMPurify.sanitize(marked.parse(raw) as string)
})

const getProgressPercent = (session: ProgressSessionApi | null) => {
    const state = session?.state
    if (!state || typeof state !== 'object') return 0

    const rawProgress = (state as Record<string, unknown>).progress_percentage ??
        (state as Record<string, unknown>).progress

    const numeric = Number(rawProgress)
    if (!Number.isFinite(numeric)) return 0
    const normalized = numeric <= 1 ? numeric * 100 : numeric
    return Math.max(0, Math.min(100, Math.round(normalized)))
}

const getCompletedModulesCount = (session: ProgressSessionApi | null) => {
    const state = session?.state
    if (!state || typeof state !== 'object') return 0
    const completedRaw = (state as Record<string, unknown>).completed_modules
    return Array.isArray(completedRaw) ? completedRaw.length : 0
}

const buildProgressReport = (session: ProgressSessionApi | null) => {
    if (!session) {
        return 'No onboarding session found for this learner and flow yet.'
    }

    const status = String(session.status || 'not_started')
    const progress = getProgressPercent(session)
    const completedModules = getCompletedModulesCount(session)
    const remaining = Math.max(0, 100 - progress)

    return [
        `**Progress Report (${roleName.value})**`,
        '',
        `1. **Current status:** ${status}`,
        `2. **Progress:** ${progress}% complete (${remaining}% remaining)`,
        `3. **Completed modules:** ${completedModules}`,
        '',
        '**Next actions:**',
        '* Continue remaining onboarding modules.',
        '* Re-run AI monitor feedback after the onboarding status becomes completed.',
    ].join('\n')
}

const websocketUrl = (id: string, userUuid?: string, flowUuid?: string) => {
    const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws'
    return `${protocol}://${window.location.host}/ws/onboarding/progress/${id}/${flowUuid}/${userUuid}/`
}

const closeMonitorSocket = () => {
    if (monitorTimeout.value !== null) {
        window.clearTimeout(monitorTimeout.value)
        monitorTimeout.value = null
    }
    if (monitorSocket.value) {
        monitorSocket.value.close()
        monitorSocket.value = null
    }
}

const runProgressMonitor = async () => {
    if (!latestSessionCompleted.value) {
        feedback.value = buildProgressReport(latestSession.value)
        monitorLogs.value = ['AI monitor skipped: onboarding is not completed yet.']
        return
    }

    monitoring.value = true
    monitorLogs.value = []

    try {
        closeMonitorSocket()
        const ws = new WebSocket(websocketUrl(roleId.value, selectedUserUuid.value || undefined, selectedFlowUuid.value || undefined))
        monitorSocket.value = ws

        await new Promise<void>((resolve, reject) => {
            let settled = false

            monitorTimeout.value = window.setTimeout(() => {
                settled = true
                ws.close()
                reject(new Error('Progress monitor timed out'))
            }, 30000)

            ws.onopen = () => {
                ws.send(JSON.stringify({action: 'progress_monitor'}),)
            }

            let streamingFeedback = false

            ws.onmessage = (event) => {
                try {
                    const payload = JSON.parse(event.data)
                    if (payload.message && payload.type !== 'stream_chunk') {
                        monitorLogs.value.push(String(payload.message))
                    }

                    if (payload.type === 'stream_chunk') {
                        if (!streamingFeedback) {
                            feedback.value = ''
                            streamingFeedback = true
                        }
                        feedback.value += payload.message || ''
                    }

                    if (payload.type === 'completed') {
                        feedback.value = String(
                            payload.content?.feedback || feedback.value || 'No feedback returned.',
                        )
                        if (monitorTimeout.value !== null) {
                            window.clearTimeout(monitorTimeout.value)
                            monitorTimeout.value = null
                        }
                        settled = true
                        ws.close()
                        resolve()
                    }

                    if (payload.type === 'error') {
                        if (monitorTimeout.value !== null) {
                            window.clearTimeout(monitorTimeout.value)
                            monitorTimeout.value = null
                        }
                        settled = true
                        ws.close()
                        reject(new Error(payload.message || 'Progress monitor failed'))
                    }
                } catch {
                    if (monitorTimeout.value !== null) {
                        window.clearTimeout(monitorTimeout.value)
                        monitorTimeout.value = null
                    }
                    settled = true
                    ws.close()
                    reject(new Error('Invalid monitor response'))
                }
            }

            ws.onerror = () => {
                if (monitorTimeout.value !== null) {
                    window.clearTimeout(monitorTimeout.value)
                    monitorTimeout.value = null
                }
                settled = true
                ws.close()
                reject(new Error('Progress monitor websocket error'))
            }

            ws.onclose = () => {
                if (monitorTimeout.value !== null) {
                    window.clearTimeout(monitorTimeout.value)
                    monitorTimeout.value = null
                }
                monitorSocket.value = null
                if (!settled) {
                    reject(new Error('Progress monitor connection closed before completion'))
                }
            }
        })
    } catch (error) {
        message.error(error instanceof Error ? error.message : 'Failed to run progress monitor')
    } finally {
        monitoring.value = false
    }
}

const loadData = async () => {
    loading.value = true
    try {
        const sessionsRes = await apiClient.get<ProgressSessionApi[]>(API.onboarding.sessions.list(), {
            params: {
                role_uuid: roleId.value,
                user_uuid: selectedUserUuid.value || undefined,
                flow_uuid: selectedFlowUuid.value || undefined,
            },
        })

        const allSessions = Array.isArray(sessionsRes.data) ? sessionsRes.data : []
        sessions.value = allSessions.sort(
            (a, b) => new Date(b.updated_at || 0).getTime() - new Date(a.updated_at || 0).getTime(),
        )

        if (sessions.value[0]?.role?.name) {
            roleName.value = String(sessions.value[0].role.name)
        }
        if (sessions.value[0]?.user?.first_name || sessions.value[0]?.user?.last_name) {
            const first = String(sessions.value[0].user.first_name || '')
            const last = String(sessions.value[0].user.last_name || '')
            learnerName.value = `${first} ${last}`.trim()
        }

        if (!sessions.value.length) {
            feedback.value = 'No onboarding session found for this learner and flow yet.'
            monitorLogs.value = []
            return
        }

        if (selectedFlowUuid.value) {
            const flowRes = await apiClient.get<FlowLookup>(
                API.onboarding.flows.byId(selectedFlowUuid.value),
            )
            flowTitle.value = String(flowRes.data?.title || '')
        }

        feedback.value = buildProgressReport(latestSession.value)
        monitorLogs.value = latestSessionCompleted.value
            ? []
            : ['AI monitor skipped: onboarding is not completed yet.']

        if (latestSessionCompleted.value) {
            await runProgressMonitor()
        }
    } catch {
        message.error('Failed to load role progress')
    } finally {
        loading.value = false
    }
}

onMounted(() => {
    loadData()
})

onBeforeUnmount(() => {
    closeMonitorSocket()
})

onBeforeRouteLeave(() => {
    closeMonitorSocket()
})
</script>

<template>
    <div class="page">
        <div class="head-row">
            <Typography.Title :level="2">Progress Details</Typography.Title>
            <Button @click="router.push('/progress')">Back to All Progress</Button>
        </div>

        <Card class="panel" :bordered="false">
            <Spin :spinning="loading" tip="Loading role progress...">
                <Typography.Title :level="4">{{ roleName }}</Typography.Title>
                <Typography.Paragraph type="secondary">
                    Learner: {{ learnerName }}
                    <span v-if="flowTitle"> | Flow: {{ flowTitle }}</span>
                </Typography.Paragraph>

                <div class="status-row">
                    <Typography.Text strong>Latest Status:</Typography.Text>
                    <Tag
                        :color="
                            latestSession?.status === 'completed'
                                ? 'green'
                                : latestSession?.status === 'active'
                                  ? 'blue'
                                  : 'default'
                        "
                    >
                        {{ latestSession?.status || 'not_started' }}
                    </Tag>
                    <Button type="primary" :loading="monitoring" @click="runProgressMonitor">
                        {{
                            latestSessionCompleted
                                ? 'Refresh Monitor Feedback'
                                : 'Refresh Progress Report'
                        }}
                    </Button>
                </div>

                <Typography.Title :level="5" style="margin-top: 1.2rem">
                    Progress Monitor Feedback
                </Typography.Title>
                <div class="feedback markdown-body" v-html="renderedFeedback"></div>

                <Typography.Title :level="5">Monitor Activity</Typography.Title>
                <List
                    size="small"
                    :data-source="monitorLogs.length ? monitorLogs : ['No monitor logs yet.']"
                >
                    <template #renderItem="{ item }">
                        <List.Item>{{ item }}</List.Item>
                    </template>
                </List>

                <Typography.Title :level="5" style="margin-top: 1.2rem">
                    Session History
                </Typography.Title>
                <List :data-source="sessions">
                    <template #renderItem="{ item }">
                        <List.Item>
                            <List.Item.Meta
                                :title="`Session ${item.uuid}`"
                                :description="item.updated_at || ''"
                            />
                            <Tag
                                :color="
                                    item.status === 'completed'
                                        ? 'green'
                                        : item.status === 'active'
                                          ? 'blue'
                                          : 'default'
                                "
                            >
                                {{ item.status }}
                            </Tag>
                        </List.Item>
                    </template>
                </List>
            </Spin>
        </Card>
    </div>
</template>

<style scoped>
.page {
    max-width: 960px;
    margin: 0 auto;
    padding: 2rem 1rem;
}
.panel {
    background: #ffffff;
    border: 1px solid #dbe3ec;
}
.head-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}
.status-row {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    flex-wrap: wrap;
}
.feedback {
    color: #6b7280;
}

.markdown-body :deep(h1),
.markdown-body :deep(h2),
.markdown-body :deep(h3),
.markdown-body :deep(h4) {
    color: #111827;
    margin: 0.75rem 0 0.5rem;
}

.markdown-body :deep(ul),
.markdown-body :deep(ol) {
    margin: 0.5rem 0 0.75rem 1.25rem;
}

.markdown-body :deep(p),
.markdown-body :deep(li) {
    color: #4b5563;
}
</style>
