import { createDropboxSyncClient } from '../core/client'
import type { DropboxCredentials, DropboxSyncClient } from '../core/types'
import { useCookie, useRuntimeConfig } from 'nuxt/app'
import type { H3Event } from 'h3'

/**
 * Helper to safely access runtime config properties
 */
function getConfigValue<T>(obj: any, path: string, defaultValue: T): T {
    const parts = path.split('.')
    let current = obj

    for (const part of parts) {
        if (current === undefined || current === null) {
            return defaultValue
        }
        current = current[part]
    }

    return (current as T) || defaultValue
}

/**
 * Nuxt-specific helper for creating a Dropbox sync client
 * Can be used in both client and server components
 */
export function useNuxtDropboxSync(
    credentials?: Partial<DropboxCredentials>
): DropboxSyncClient {
    // Get Nuxt runtime config (for client ID and secret)
    const config = useRuntimeConfig()

    // Create base credentials with defaults from runtime config
    const baseCredentials: DropboxCredentials = {
        clientId: getConfigValue<string>(config, 'public.dropboxAppKey', ''),
        clientSecret: getConfigValue<string | undefined>(
            config,
            'dropboxAppSecret',
            ''
        ),
        ...credentials,
    }

    // On client-side, attempt to get tokens from cookies
    if (process.client) {
        const accessToken = useCookie('dropbox_access_token')
        const refreshToken = useCookie('dropbox_refresh_token')

        if (accessToken.value && !baseCredentials.accessToken) {
            baseCredentials.accessToken = accessToken.value as string
        }

        if (refreshToken.value && !baseCredentials.refreshToken) {
            baseCredentials.refreshToken = refreshToken.value as string
        }
    }

    return createDropboxSyncClient(baseCredentials)
}

/**
 * Server-side helper to get credentials from Nuxt server event
 */
export function getCredentialsFromCookies(event: H3Event): DropboxCredentials {
    const config = useRuntimeConfig()

    // Get cookies from Nuxt server event
    const accessToken = getCookie(event, 'dropbox_access_token')
    const refreshToken = getCookie(event, 'dropbox_refresh_token')

    return {
        clientId: getConfigValue<string>(config, 'public.dropboxAppKey', ''),
        clientSecret: getConfigValue<string | undefined>(
            config,
            'dropboxAppSecret',
            ''
        ),
        accessToken,
        refreshToken,
    }
}

/**
 * Create API event handlers for a Nuxt app
 */
export function createNuxtApiHandlers() {
    return {
        /**
         * Handler for status check endpoint
         */
        async status(event: H3Event) {
            const accessToken = getCookie(event, 'dropbox_access_token')
            const isConnected = !!accessToken

            return { connected: isConnected }
        },

        /**
         * Handler for OAuth start endpoint
         */
        async oauthStart(event: H3Event) {
            const config = useRuntimeConfig()

            const dropboxSync = createDropboxSyncClient({
                clientId: getConfigValue<string>(
                    config,
                    'public.dropboxAppKey',
                    ''
                ),
            })

            const redirectUri =
                getConfigValue<string>(config, 'dropboxRedirectUri', '') ||
                `${getConfigValue<string>(
                    config,
                    'public.appUrl',
                    'http://localhost:3000'
                )}/api/dropbox/auth/callback`

            const authUrl = await dropboxSync.auth.getAuthUrl(redirectUri)

            return sendRedirect(event, authUrl)
        },

        /**
         * Handler for OAuth callback endpoint
         */
        async oauthCallback(event: H3Event) {
            const config = useRuntimeConfig()

            // Get the authorization code from query parameters
            const query = getQuery(event)
            const code = query.code as string

            if (!code) {
                return sendRedirect(event, '/auth/error')
            }

            const redirectUri =
                getConfigValue<string>(config, 'dropboxRedirectUri', '') ||
                `${getConfigValue<string>(
                    config,
                    'public.appUrl',
                    'http://localhost:3000'
                )}/api/dropbox/auth/callback`

            const dropboxSync = createDropboxSyncClient({
                clientId: getConfigValue<string>(
                    config,
                    'public.dropboxAppKey',
                    ''
                ),
                clientSecret: getConfigValue<string | undefined>(
                    config,
                    'dropboxAppSecret',
                    ''
                ),
            })

            try {
                const tokens = await dropboxSync.auth.exchangeCodeForToken(
                    code,
                    redirectUri
                )

                // Set cookies with the tokens
                setCookie(event, 'dropbox_access_token', tokens.accessToken, {
                    httpOnly: true,
                    secure: process.env.NODE_ENV === 'production',
                    maxAge: tokens.expiresAt
                        ? Math.floor((tokens.expiresAt - Date.now()) / 1000)
                        : 14 * 24 * 60 * 60, // 14 days default
                    sameSite: 'lax',
                    path: '/',
                })

                if (tokens.refreshToken) {
                    setCookie(
                        event,
                        'dropbox_refresh_token',
                        tokens.refreshToken,
                        {
                            httpOnly: true,
                            secure: process.env.NODE_ENV === 'production',
                            maxAge: 365 * 24 * 60 * 60, // 1 year
                            sameSite: 'lax',
                            path: '/',
                        }
                    )
                }

                // Set a non-httpOnly cookie to indicate connection status to the client
                setCookie(event, 'dropbox_connected', 'true', {
                    secure: process.env.NODE_ENV === 'production',
                    maxAge: tokens.expiresAt
                        ? Math.floor((tokens.expiresAt - Date.now()) / 1000)
                        : 14 * 24 * 60 * 60,
                    sameSite: 'lax',
                    path: '/',
                })

                return sendRedirect(event, '/')
            } catch (error) {
                console.error('Error completing Dropbox OAuth flow:', error)
                return sendRedirect(event, '/auth/error')
            }
        },

        /**
         * Handler for logout endpoint
         */
        async logout(event: H3Event) {
            // Clear all Dropbox-related cookies
            deleteCookie(event, 'dropbox_access_token')
            deleteCookie(event, 'dropbox_refresh_token')
            deleteCookie(event, 'dropbox_connected')

            return { success: true }
        },
    }
}

/**
 * Helper functions to work with Nuxt's H3Event
 * These import statements need to be added to avoid reference errors
 */
const { getCookie, setCookie, deleteCookie } = useNuxtCookies()
const { getQuery, sendRedirect } = useNuxtServer()

/**
 * Helper to access h3 cookie methods
 */
function useNuxtCookies() {
    return {
        getCookie: (event: H3Event, name: string) => {
            // Import inside function to avoid module loading issues
            const { getCookie } = require('h3')
            return getCookie(event, name)
        },
        setCookie: (
            event: H3Event,
            name: string,
            value: string,
            options?: any
        ) => {
            const { setCookie } = require('h3')
            return setCookie(event, name, value, options)
        },
        deleteCookie: (event: H3Event, name: string, options?: any) => {
            const { deleteCookie } = require('h3')
            return deleteCookie(event, name, { ...options, path: '/' })
        },
    }
}

/**
 * Helper to access h3 server methods
 */
function useNuxtServer() {
    return {
        getQuery: (event: H3Event) => {
            const { getQuery } = require('h3')
            return getQuery(event)
        },
        sendRedirect: (event: H3Event, location: string) => {
            const { sendRedirect } = require('h3')
            return sendRedirect(event, location)
        },
    }
}
