import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { apiClient, isAxiosError, API } from '../router/api'
import type { User, SessionResponse } from '../types/user'
import type { Organization, Role } from 'src/types/organization'

const orgUuidKey = 'userSelectedOrganizationUuid'

export const useUserStore = defineStore('user', () => {
    const isAuthenticated = ref(false)
    const isAdmin = ref(false)
    const isGeneralManager = computed(() => {
        if (!isAuthenticated.value || !user.value) return false
        return user.value.is_manager
    })

    const loading = ref(false)
    const error = ref<string | null>(null)

    const user = ref<User | null>(null)
    const userJoinedOrganizations = ref<Organization[]>([])
    const userSelectedOrganization = ref<Organization | null>(null)
    const userJoinedRoles = ref<Role[]>([])

    const displayName = computed(() => {
        if (!user.value) return ''
        return `${user.value.first_name} ${user.value.last_name}`
    })

    const setUser = (userData: User | null) => {
        user.value = userData
        isAuthenticated.value = !!userData
    }

    const setJoinedOrganizations = (organizations: Organization[]) => {
        userJoinedOrganizations.value = organizations
        if (organizations.length > 0) {
            const stored = localStorage.getItem(orgUuidKey)
            const matched = organizations.find((org) => org.uuid === stored)
            if (matched) {
                userSelectedOrganization.value = matched
                return
            }
            userSelectedOrganization.value = organizations[0]
            localStorage.setItem(orgUuidKey, organizations[0].uuid)
        } else {
            userSelectedOrganization.value = null
            localStorage.removeItem(orgUuidKey)
        }
    }

    const setSelectedOrganization = (organization: Organization | null) => {
        userSelectedOrganization.value = organization
        if (organization) {
            localStorage.setItem(orgUuidKey, organization.uuid)
        } else {
            localStorage.removeItem(orgUuidKey)
        }
    }

    const fetchSession = async (force = false) => {
        if (isAuthenticated.value && !force) return user.value
        loading.value = true
        error.value = null
        try {
            const response = await apiClient.get<SessionResponse>(API.auth.session())
            if (response.data?.isAuthenticated) {
                const userData = await apiClient.get<User>(API.auth.me())
                setUser(userData.data)
                await fetchJoinedOrganizations()
            } else {
                setUser(null)
                isAuthenticated.value = false
            }
            return user.value
        } catch (err: unknown) {
            if (isAxiosError(err)) {
                error.value = err.response?.data?.detail || err.response?.data?.error || err.message
            } else if (err instanceof Error) {
                error.value = err.message
            } else {
                error.value = String(err)
            }
            setUser(null)
            throw err
        } finally {
            loading.value = false
        }
    }

    const fetchJoinedOrganizations = async () => {
        if (!user.value) return
        try {
            const response = await apiClient.get<Organization[]>(API.organization.list())
            setJoinedOrganizations(response.data)
            return response.data
        } catch (err: unknown) {
            console.error('Failed to fetch organizations', err)
            setJoinedOrganizations([])
            return []
        }
    }

    const fetchJoinedRoles = async () => {
        if (!user.value || !userSelectedOrganization.value) return
        try {
            const response = await apiClient.get<Role[]>(
                API.organization.roles.list(userSelectedOrganization.value.uuid),
            )
            setJoinedRoles(response.data)
            return response.data
        } catch (err: unknown) {
            console.error('Failed to fetch role memberships', err)
            setJoinedRoles([])
            return []
        }
    }

    const setJoinedRoles = (roles: Role[]) => {
        userJoinedRoles.value = roles
    }

    const login = async (emailAddress: string, password: string) => {
        loading.value = true
        error.value = null
        try {
            const res = await apiClient.post<{
                user: User
                message?: string
            }>(API.auth.login(), { email_address: emailAddress, password })
            setUser(res.data?.user ?? null)
            return res.data
        } catch (err: unknown) {
            if (isAxiosError(err)) {
                error.value = err.response?.data?.error || err.response?.data?.detail || err.message
            } else if (err instanceof Error) {
                error.value = err.message
            } else {
                error.value = String(err)
            }
            throw err
        } finally {
            loading.value = false
        }
    }

    const register = async (payload: {
        email_address: string
        password: string
        confirm_password?: string
        first_name: string
        last_name: string
        date_of_birth?: string
        manager: boolean
    }) => {
        loading.value = true
        error.value = null
        try {
            await apiClient.post(API.auth.signup(), payload)
            await login(payload.email_address, payload.password)
        } catch (err: unknown) {
            if (isAxiosError(err)) {
                error.value = err.response?.data?.detail || err.response?.data?.error || err.message
            } else if (err instanceof Error) {
                error.value = err.message
            } else {
                error.value = String(err)
            }
            throw err
        } finally {
            loading.value = false
        }
    }

    const logout = async () => {
        loading.value = true
        error.value = null
        try {
            await apiClient.post(API.auth.logout())
        } catch (err: unknown) {
            if (isAxiosError(err)) {
                error.value = err.response?.data?.detail || err.response?.data?.error || err.message
            } else if (err instanceof Error) {
                error.value = err.message
            } else {
                error.value = String(err)
            }
            throw err
        } finally {
            setUser(null)
            loading.value = false
        }
    }

    return {
        user,
        displayName,
        isAuthenticated,
        isAdmin,
        isGeneralManager,
        loading,
        error,
        userJoinedOrganizations,
        userSelectedOrganization,
        userJoinedRoles,

        setUser,
        fetchSession,
        setJoinedOrganizations,
        setSelectedOrganization,
        setJoinedRoles,
        fetchJoinedOrganizations,
        fetchJoinedRoles,
        login,
        register,
        logout,
    }
})
