<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, computed, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useDocumentVisibility, useEventListener, useIntervalFn } from '@vueuse/core'
import {
    Card,
    Typography,
    Button,
    List,
    Space,
    Spin,
    message,
    Tag,
    Divider,
    Modal,
} from 'ant-design-vue'
import { apiClient, isAxiosError, API } from '../router/api'
import { useUserStore } from '../stores/userStore'
import type { Role, Organization } from '../types/organization'

const router = useRouter()
const route = useRoute()
const organizationUuid = computed(() => String(route.params.organizationUuid || ''))

const organization = ref<Organization | null>(null)
const roles = ref<Role[]>([])
const members = ref<Array<{ uuid: string; is_manager?: boolean }>>([])
const loading = ref(false)
const leavingOrganization = ref(false)
const rolePollingMs = 12000
const auth = useUserStore()
const visibility = useDocumentVisibility()
const pollingInFlight = ref(false)
let stopVisibilityListener: (() => void) | null = null

const isManager = computed(() => {
    if (!auth.user || !organization.value) return false
    if ((organization.value as Organization & { is_manager?: boolean }).is_manager === true)
        return true
    if (organization.value.owner?.uuid === auth.user.uuid) return true
    return members.value.some((member) => member.uuid === auth.user?.uuid && member.is_manager)
})

const isOwner = computed(() => {
    if (!auth.user || !organization.value) return false
    return organization.value.owner?.uuid === auth.user.uuid
})

const canLeaveCurrentOrganization = computed(() => {
    if (!organization.value) return false
    if (!isOwner.value) return true
    return (organization.value.member_count ?? 0) <= 1
})

const fetchOrganization = async () => {
    loading.value = true
    try {
        if (!organizationUuid.value) {
            organization.value = null
            return
        }
        const response = await apiClient.get<Organization>(API.organization.byId(organizationUuid.value))
        organization.value = response.data
        auth.setSelectedOrganization(response.data)
    } catch (error) {
        console.error('Failed to fetch organization:', error)
        message.error('Failed to load organization details')
    } finally {
        loading.value = false
    }
}

const fetchRoles = async () => {
    if (!organization.value?.uuid) return
    try {
        const response = await apiClient.get<Role[]>(API.roles.list(organization.value.uuid))
        roles.value = response.data
    } catch (error) {
        console.error('Failed to fetch roles:', error)
    }
}

const fetchUserRoleMemberships = async () => {
    if (!organization.value?.uuid) return
    try {
        const response = await apiClient.get<Role[]>(API.roles.mine())
        const mine = Array.isArray(response.data) ? response.data : []
        const orgUuid = organization.value.uuid
        const joinedRoles = mine.filter((role) => role.organization?.uuid === orgUuid)
        auth.setJoinedRoles(joinedRoles)
    } catch (err) {
        console.error('Failed to fetch user role memberships', err)
    }
}

const isRoleJoined = (roleUuid: string | undefined) => {
    if (!roleUuid) return false
    return auth.userJoinedRoles.some((role) => role.uuid === roleUuid)
}

const canStartOnboarding = (roleUuid: string | undefined) => {
    if (!roleUuid) return false
    if (isManager.value) return true
    return isRoleJoined(roleUuid)
}

const startOnboarding = (roleUuid: string | undefined) => {
    if (!roleUuid) return

    if (!canStartOnboarding(roleUuid)) {
        message.warning('Join this role before starting onboarding.')
        return
    }

    router.push(`/onboarding/${roleUuid}`)
}

const fetchMembers = async () => {
    if (!organization.value?.uuid) return
    try {
        const response = await apiClient.get<Array<{ uuid: string; is_manager?: boolean }>>(
            API.organization.members.list(organization.value.uuid),
        )
        members.value = response.data
    } catch (error) {
        console.error('Failed to fetch members:', error)
    }
}

const selectRole = async (roleUuid: string) => {
    if (!organization.value?.uuid) {
        message.error('Organization not loaded')
        return
    }
    if (isManager.value) {
        message.error('Managers cannot join roles from this page')
        return
    }
    if (!auth.user?.uuid) {
        try {
            await auth.fetchSession(true)
        } catch {
            message.error('You must be signed in to join a role')
            return
        }
    }
    if (auth.userJoinedRoles.some((role) => role.uuid === roleUuid)) {
        message.info('You are already a member of this role')
        return
    }

    try {
        await apiClient.post(API.roles.join(organization.value.uuid, roleUuid))
        message.success('Successfully joined role')

        const joinedRole = roles.value.find((role) => role.uuid === roleUuid)
        if (joinedRole) {
            joinedRole.member_count = (joinedRole.member_count ?? 0) + 1
        }

        if (!auth.userJoinedRoles.some((role) => role.uuid === roleUuid)) {
            auth.setJoinedRoles([
                ...auth.userJoinedRoles,
                roles.value.find((role) => role.uuid === roleUuid)!,
            ])
        }

        await fetchRoles()
    } catch (error) {
        console.error('Failed to join role:', error)
        if (isAxiosError(error)) {
            message.error(error.response?.data?.error || 'Failed to join role')
        }
    }
}

const loadOrganizationContext = async () => {
    await auth.fetchSession(true)
    await fetchOrganization()
    await fetchMembers()
    await fetchRoles()
    await fetchUserRoleMemberships()
}

const canPollRoles = () => Boolean(organization.value?.uuid)

const refreshRolesLive = async () => {
    if (pollingInFlight.value || !canPollRoles()) return
    pollingInFlight.value = true
    try {
        await Promise.all([fetchRoles(), fetchUserRoleMemberships()])
    } finally {
        pollingInFlight.value = false
    }
}

const { pause: stopRolePolling, resume: resumeRolePolling } = useIntervalFn(
    () => {
        void refreshRolesLive()
    },
    rolePollingMs,
    { immediate: false, immediateCallback: false },
)

const startRolePolling = () => {
    stopRolePolling()
    if (visibility.value !== 'visible' || !canPollRoles()) return
    resumeRolePolling()
}

const bindVisibility = () => {
    if (stopVisibilityListener) return
    stopVisibilityListener = useEventListener(document, 'visibilitychange', () => {
        if (visibility.value !== 'visible') {
            stopRolePolling()
            return
        }

        void refreshRolesLive()
        if (canPollRoles()) {
            resumeRolePolling()
        }
    })
}

const unbindVisibility = () => {
    if (!stopVisibilityListener) return
    stopVisibilityListener()
    stopVisibilityListener = null
}

const leaveOrganization = () => {
    if (!organization.value) return

    Modal.confirm({
        title: 'Leave organization',
        content: isOwner.value
            ? 'As owner, leaving will delete this organization because no other members remain. Continue?'
            : `Are you sure you want to leave "${organization.value.name}"?`,
        okText: 'Leave',
        okType: 'danger',
        cancelText: 'Cancel',
        onOk: async () => {
            if (!organization.value) return

            leavingOrganization.value = true
            try {
                await apiClient.post(API.organization.leave(organization.value.uuid))
                message.success(
                    isOwner.value
                        ? 'Organization deleted and ownership closed.'
                        : 'You left the organization.',
                )
                auth.setJoinedRoles([])
                await auth.fetchJoinedOrganizations()
                await router.push('/organization')
            } catch (error) {
                console.error('Failed to leave organization:', error)
                if (isAxiosError(error)) {
                    message.error(error.response?.data?.error || 'Failed to leave organization')
                } else {
                    message.error('Failed to leave organization')
                }
            } finally {
                leavingOrganization.value = false
            }
        },
    })
}

onMounted(async () => {
    await loadOrganizationContext()
    bindVisibility()
    startRolePolling()
})

onBeforeUnmount(() => {
    stopRolePolling()
    unbindVisibility()
})

watch(
    () => organizationUuid.value,
    async (next, prev) => {
        if (!next || next === prev) return
        stopRolePolling()
        roles.value = []
        members.value = []
        await loadOrganizationContext()
        startRolePolling()
    },
)
</script>

<template>
    <div class="page">
        <Spin :spinning="loading" tip="Loading organization...">
            <Card v-if="organization" class="panel" :bordered="false">
                <div class="header">
                    <Typography.Title :level="2">{{ organization.name }}</Typography.Title>
                    <Space>
                        <Button
                            v-if="isManager"
                            type="primary"
                            @click="router.push(`/organization/${organization.uuid}/manage`)"
                        >
                            Manage Organization
                        </Button>
                        <Button
                            danger
                            :loading="leavingOrganization"
                            :disabled="!canLeaveCurrentOrganization"
                            :title="
                                !canLeaveCurrentOrganization
                                    ? 'Owner can leave only when no other members/managers remain.'
                                    : 'Leave organization'
                            "
                            @click="leaveOrganization"
                        >
                            Leave Organization
                        </Button>
                    </Space>
                </div>

                <Typography.Paragraph v-if="organization.description">
                    {{ organization.description }}
                </Typography.Paragraph>
                <Typography.Paragraph v-else type="secondary">
                    No description provided
                </Typography.Paragraph>

                <Space direction="vertical" :size="4" style="margin: 1rem 0">
                    <div>
                        <Typography.Text strong>Owner:</Typography.Text>
                        {{ organization.owner?.first_name }} {{ organization.owner?.last_name }}
                    </div>
                    <div>
                        <Typography.Text strong>Members:</Typography.Text>
                        {{ organization.member_count ?? 0 }}
                    </div>
                    <div>
                        <Typography.Text strong>Roles:</Typography.Text>
                        {{ organization.role_count ?? 0 }}
                    </div>
                </Space>

                <Divider />

                <Typography.Title :level="4" class="section-title">
                    Available Roles
                </Typography.Title>

                <div v-if="roles.length > 0">
                    <List :data-source="roles" :bordered="false">
                        <template #renderItem="{ item }">
                            <List.Item class="role-item">
                                <List.Item.Meta :title="item.name" />
                                <Space>
                                    <Tag color="cyan">{{ item.member_count ?? 0 }} members</Tag>
                                    <Button
                                        type="default"
                                        size="small"
                                        :disabled="!canStartOnboarding(item.uuid)"
                                        :title="
                                            !canStartOnboarding(item.uuid)
                                                ? 'Join this role before starting onboarding.'
                                                : 'Start onboarding'
                                        "
                                        @click="startOnboarding(item.uuid)"
                                    >
                                        {{ canStartOnboarding(item.uuid) ? 'Start Onboarding' : 'Join Role First' }}
                                    </Button>
                                    <Button
                                        v-if="!isManager && item.uuid && !isRoleJoined(item.uuid)"
                                        type="primary"
                                        size="small"
                                        @click="selectRole(item.uuid)"
                                    >
                                        Join Role
                                    </Button>
                                    <Button
                                        v-else-if="!isManager"
                                        size="small"
                                        disabled
                                    >
                                        Joined
                                    </Button>
                                </Space>
                            </List.Item>
                        </template>
                    </List>
                </div>
                <Typography.Paragraph v-else type="secondary">
                    No roles available in this organization.
                </Typography.Paragraph>
            </Card>
        </Spin>

    </div>
</template>

<style scoped>
.page {
    padding: 1rem;
}

.header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1rem;
}

.section-title {
    margin-top: 1.5rem !important;
    margin-bottom: 1rem !important;
}

.role-item :deep(.ant-list-item-meta-title),
.role-item :deep(.ant-list-item-meta-description) {
    color: #1f2937;
}

.role-item {
    border-bottom: none !important;
}
</style>
