import { defineStore } from "pinia"
import router from "#app/plugins/router";
import {Preferences} from "@capacitor/preferences";

export const useAuthStore = defineStore("auth", {
    state: () => ({
        user: null as null | {
            id?: string;
            user_id?: string;
            email: string;
            tenant_id?: string;
            role?: string;
            must_change_password?: boolean;
            is_admin?: boolean;
        },
        profile: null as null | any,
        tenants: [] as { tenant_id: string; role: string; tenants: { id: string; name: string }; id?: string; name?: string; hasActiveLicense?: boolean; locked?: string | null }[],
        permissions: [] as string[],
        activeTenant: null as any,
        activeTenantData: null as any,
        loading: true as boolean,
        notLoggedIn: true,
        sessionExpired: false,
        sessionWarningVisible: false,
        sessionWarningRemainingSeconds: 0,
        sessionWarningLeadMs: 5 * 60 * 1000,
        sessionWarningTimer: null as ReturnType<typeof setTimeout> | null,
        sessionLogoutTimer: null as ReturnType<typeof setTimeout> | null,
        sessionCountdownTimer: null as ReturnType<typeof setInterval> | null,
        sessionPersistent: false,
    }),

    actions: {
        tokenCookie() {
            return useCookie<string | null>("token", { path: "/" })
        },

        getStoredToken() {
            const rootToken = this.tokenCookie().value
            if (!process.client) return rootToken

            return sessionStorage.getItem("token")
                || localStorage.getItem("token")
                || rootToken
        },

        getStoredRefreshToken() {
            if (!process.client) return null

            return sessionStorage.getItem("refreshToken")
                || localStorage.getItem("refreshToken")
        },

        clearScopedTokenCookies() {
            if (!process.client) return

            const pathname = window.location.pathname || "/"
            const pathParts = pathname.split("/").filter(Boolean)
            const paths = new Set(["/"])

            pathParts.reduce((path, part) => {
                const nextPath = `${path === "/" ? "" : path}/${part}`
                paths.add(nextPath)
                return nextPath
            }, "/")

            paths.forEach((path) => {
                document.cookie = `token=; Max-Age=0; path=${path}`
            })
        },

        decodeTokenExpiryMs(token: string) {
            try {
                const parts = token.split(".")
                if (parts.length < 2) return null

                const payload = JSON.parse(atob(parts[1].replace(/-/g, "+").replace(/_/g, "/")))
                if (!payload?.exp) return null

                return Number(payload.exp) * 1000
            } catch (err) {
                console.error("Could not decode token expiry", err)
                return null
            }
        },

        clearSessionTimers() {
            if (!process.client) return

            if (this.sessionWarningTimer) {
                clearTimeout(this.sessionWarningTimer)
                this.sessionWarningTimer = null
            }

            if (this.sessionLogoutTimer) {
                clearTimeout(this.sessionLogoutTimer)
                this.sessionLogoutTimer = null
            }

            if (this.sessionCountdownTimer) {
                clearInterval(this.sessionCountdownTimer)
                this.sessionCountdownTimer = null
            }
        },

        startSessionCountdown(expiresAtMs: number) {
            if (!process.client) return

            if (this.sessionCountdownTimer) {
                clearInterval(this.sessionCountdownTimer)
            }

            this.sessionCountdownTimer = setInterval(() => {
                const remaining = Math.max(0, Math.ceil((expiresAtMs - Date.now()) / 1000))
                this.sessionWarningRemainingSeconds = remaining

                if (remaining <= 0 && this.sessionCountdownTimer) {
                    clearInterval(this.sessionCountdownTimer)
                    this.sessionCountdownTimer = null
                }
            }, 1000)
        },

        openSessionWarning(expiresAtMs: number) {
            this.sessionWarningVisible = true
            this.sessionWarningRemainingSeconds = Math.max(0, Math.ceil((expiresAtMs - Date.now()) / 1000))
            this.startSessionCountdown(expiresAtMs)
        },

        scheduleSessionTimers(token?: string | null) {
            if (!process.client) return

            const tokenToUse = token || this.getStoredToken()

            this.clearSessionTimers()
            this.sessionWarningVisible = false
            this.sessionWarningRemainingSeconds = 0

            if (!tokenToUse) return

            const expiresAtMs = this.decodeTokenExpiryMs(tokenToUse)
            if (!expiresAtMs) return

            const now = Date.now()
            const msUntilLogout = expiresAtMs - now

            if (msUntilLogout <= 0) {
                this.expireSession()
                return
            }

            this.sessionLogoutTimer = setTimeout(() => {
                this.expireSession()
            }, msUntilLogout)

            const msUntilWarning = msUntilLogout - this.sessionWarningLeadMs

            if (msUntilWarning <= 0) {
                if (this.getStoredRefreshToken()) {
                    void this.refreshSession()
                    return
                }
                this.openSessionWarning(expiresAtMs)
                return
            }

            this.sessionWarningTimer = setTimeout(() => {
                if (this.getStoredRefreshToken()) {
                    void this.refreshSession()
                    return
                }
                this.openSessionWarning(expiresAtMs)
            }, msUntilWarning)
        },

        setToken(token: string | null, persistent = this.sessionPersistent) {
            this.clearScopedTokenCookies()
            this.tokenCookie().value = token

            if (process.client) {
                localStorage.removeItem("token")
                sessionStorage.removeItem("token")

                if (token) {
                    const storage = persistent ? localStorage : sessionStorage
                    storage.setItem("token", token)
                }
            }

            if (!token) {
                this.clearSessionTimers()
                this.sessionWarningVisible = false
                this.sessionWarningRemainingSeconds = 0
                return
            }

            this.scheduleSessionTimers(token)
        },

        setRefreshToken(refreshToken: string | null, persistent = this.sessionPersistent) {
            if (!process.client) return

            localStorage.removeItem("refreshToken")
            sessionStorage.removeItem("refreshToken")

            if (refreshToken) {
                const storage = persistent ? localStorage : sessionStorage
                storage.setItem("refreshToken", refreshToken)
            }
        },

        setSession(token: string, refreshToken: string, persistent: boolean) {
            this.sessionPersistent = persistent
            this.setRefreshToken(refreshToken, persistent)
            this.setToken(token, persistent)
        },

        clearStoredSession() {
            this.setRefreshToken(null)
            this.setToken(null)
            this.sessionPersistent = false
        },

        async persist(token: string | null) {

            console.log("On Web")
            this.setToken(token)

        },

        async initStore() {
            console.log("Auth initStore")
            this.sessionPersistent = process.client && Boolean(localStorage.getItem("refreshToken"))

            // 1. Check: Haben wir überhaupt ein Token?
            const token = this.getStoredToken()

            if (!token) {
                // Kein Token -> Wir sind fertig, User ist Gast.
                this.user = null
                this.loading = false
                return
            }

            // 2. Token existiert -> Versuche User zu laden
            await this.fetchMe(token, true)

            // Wenn fetchMe fertig ist (egal ob Erfolg oder Fehler), ladebalken weg


            // Optional: Wenn eingeloggt, leite zur Home, falls gewünscht
            if(this.activeTenant > 0) {
                this.loading = false
                // Hier vorsichtig sein: Nicht navigieren, wenn der User auf eine Deep-Link URL will!
                // navigateTo("/")  <-- Das würde ich hier evtl. sogar weglassen und der Middleware überlassen
            }

            this.loading = false
        },

        async init(token=null) {
            console.log("Auth init")
            await this.fetchMe(token)

            const tempStore = useTempStore()

            if(this.profile?.temp_config) tempStore.setStoredTempConfig(this.profile.temp_config)
            if(this.activeTenant > 0) {
                this.loading = false

                navigateTo("/")
            }
        },

        async login(email: string, password: string, rememberMe = false) {
            try {
                console.log("Auth login")
                const { token, refreshToken } = await useNuxtApp().$api("/auth/login", {
                    method: "POST",
                    body: { email, password, rememberMe }
                })

                console.log("Token: " + token)

                // Tokens abhängig von „Angemeldet bleiben“ dauerhaft oder nur für diese Sitzung speichern
                this.setSession(token, refreshToken, rememberMe)
                this.sessionExpired = false

                // 2. User Daten laden
                await this.fetchMe(token)

                console.log(this.user)

                // 3. WICHTIG: Jetzt explizit weiterleiten!
                // Prüfen, ob der User geladen wurde
                if (this.user) {
                    // Falls Passwort-Änderung erzwungen wird (passend zu deiner Middleware)
                    if (this.user.must_change_password) {
                        return navigateTo("/password-change")
                    }

                    // Normaler Login -> Dashboard
                    return navigateTo("/")
                }

            } catch (e) {
                console.log("login error:" + e)
                throw e
            }
        },

        async logout() {
            console.log("Auth logout")
            const refreshToken = this.getStoredRefreshToken()
            try {
                await useNuxtApp().$api("/auth/logout", {
                    method: "POST",
                    body: { refreshToken }
                })
            } catch (e) {
                console.error("Logout API fehlgeschlagen (egal):", e)
            }

            // State resetten
            this.resetState()

            // Token löschen
            this.clearStoredSession()

            // Nur beim expliziten Logout navigieren wir
            navigateTo("/login")
        },

        expireSession() {
            console.log("Auth session expired")
            this.resetState()
            this.sessionExpired = true
            this.clearStoredSession()
            this.loading = false

            if (process.client) {
                navigateTo("/login")
            }
        },

        resetState() {
            this.clearSessionTimers()
            this.user = null
            this.permissions = []
            this.profile = null
            this.activeTenant = null
            this.tenants = []
            this.activeTenantData = null
            this.sessionExpired = false
            this.sessionWarningVisible = false
            this.sessionWarningRemainingSeconds = 0
            this.loading = false
        },

        async fetchMe(jwt= null, allowRefresh = true) {
            console.log("Auth fetchMe")
            const tempStore = useTempStore()

            // Token aus Argument oder Cookie holen
            const tokenToUse = jwt || this.getStoredToken()

            if (!tokenToUse) {
                const wasSessionExpired = this.sessionExpired
                this.resetState()
                this.sessionExpired = wasSessionExpired
                return
            }

            try {
                const me = await useNuxtApp().$api("/api/me", {
                    headers: {
                        Authorization: `Bearer ${tokenToUse}`,
                        context: { jwt: tokenToUse }
                    }
                })

                // ... (Deine Logik für tenants, sorting etc. bleibt gleich) ...
                console.log(me)
                this.user = me.user
                this.permissions = me.permissions
                this.tenants = me.tenants

                this.tenants.sort(function (a, b) {
                    if (a.id < b.id)  return -1
                    if (a.id > b.id)  return 1
                })

                this.profile = me.profile

                if(this.profile?.temp_config) tempStore.setStoredTempConfig(this.profile.temp_config)

                if(me.activeTenant > 0) {
                    const normalizedActiveTenant = String(me.activeTenant)
                    this.activeTenant = normalizedActiveTenant
                    this.activeTenantData = me.tenants.find(i => String(i.id) === normalizedActiveTenant) || null

                    try {
                        const tenant = await useNuxtApp().$api("/api/tenant", {
                            headers: {
                                Authorization: `Bearer ${tokenToUse}`,
                                context: { jwt: tokenToUse }
                            }
                        })

                        if (tenant?.id) {
                            this.activeTenantData = tenant
                        }
                    } catch (tenantError) {
                        console.error("fetch active tenant failed", tenantError)
                    }
                }

                this.scheduleSessionTimers(tokenToUse)

                console.log(this)

            } catch (err: any) {
                // WICHTIG: Hier NICHT this.logout() aufrufen, weil das navigiert!
                console.log("fetchMe failed (Invalid Token or Network)", err)

                if (err?.response?.status === 401 || err?.status === 401 || err?.statusCode === 401) {
                    if (allowRefresh && this.getStoredRefreshToken()) {
                        await this.refreshSession()
                        return
                    }
                    this.expireSession()
                    return
                }

                this.loading = false

                // Wir werfen den Fehler nicht weiter, damit initStore normal durchläuft
            }
        },

        async refreshSession() {
            const refreshToken = this.getStoredRefreshToken()
            if (!refreshToken) {
                this.expireSession()
                return
            }

            try {
                const session = await useNuxtApp().$api("/auth/refresh", {
                    method: "POST",
                    body: { refreshToken }
                })

                this.setSession(session.token, session.refreshToken, this.sessionPersistent)
                await this.fetchMe(session.token, false)
                this.sessionWarningVisible = false
            } catch (err) {
                console.error("JWT refresh failed", err)
                const status = err?.response?.status || err?.status || err?.statusCode
                if (status === 401) {
                    this.expireSession()
                } else {
                    const token = this.getStoredToken()
                    const expiresAtMs = token ? this.decodeTokenExpiryMs(token) : null
                    if (expiresAtMs) this.openSessionWarning(expiresAtMs)
                }
            }
        },

        async switchTenant(tenant_id: string) {
            console.log("Auth switchTenant")
            this.loading = true
            const res = await useNuxtApp().$api("/api/tenant/switch", {
                method: "POST",
                body: {
                    tenant_id,
                    refreshToken: this.getStoredRefreshToken()
                }
            })
            console.log(res)

            const {token, refreshToken} = res
            this.setSession(token, refreshToken, this.sessionPersistent)


            await this.init(token)
        },

        hasPermission(key: string) {
            return this.permissions.includes(key)
        }
    }
})
