import {
    useSvelteDropboxSync,
    getCredentialsFromCookies,
    createSvelteKitHandlers,
} from '../svelte'
import { createDropboxSyncClient } from '../../core/client'
import type { Cookies } from '@sveltejs/kit'

// Mock dependencies
jest.mock('../../core/client')

describe('SvelteKit adapter', () => {
    beforeEach(() => {
        jest.clearAllMocks()

        // Mock process.env
        process.env.DROPBOX_APP_KEY = 'test-app-key'
        process.env.DROPBOX_APP_SECRET = 'test-app-secret'
        process.env.PUBLIC_APP_URL = 'https://example.com'
    })

    describe('useSvelteDropboxSync', () => {
        it('should create a Dropbox sync client with provided credentials', () => {
            const mockCredentials = {
                clientId: 'custom-client-id',
                clientSecret: 'custom-client-secret',
            }

            ;(createDropboxSyncClient as jest.Mock).mockReturnValue({
                mock: 'client',
            })

            const result = useSvelteDropboxSync(mockCredentials)

            expect(createDropboxSyncClient).toHaveBeenCalledWith(
                mockCredentials
            )
            expect(result).toEqual({ mock: 'client' })
        })
    })

    describe('getCredentialsFromCookies', () => {
        it('should get credentials from cookies', () => {
            const mockCookies = {
                get: jest.fn((name) => {
                    if (name === 'dropbox_access_token')
                        return 'test-access-token'
                    if (name === 'dropbox_refresh_token')
                        return 'test-refresh-token'
                    return null
                }),
            } as unknown as Cookies

            const credentials = getCredentialsFromCookies(mockCookies)

            expect(mockCookies.get).toHaveBeenCalledWith('dropbox_access_token')
            expect(mockCookies.get).toHaveBeenCalledWith(
                'dropbox_refresh_token'
            )
            expect(credentials).toEqual({
                clientId: 'test-app-key',
                clientSecret: 'test-app-secret',
                accessToken: 'test-access-token',
                refreshToken: 'test-refresh-token',
            })
        })
    })

    describe('createSvelteKitHandlers', () => {
        it('should create SvelteKit handlers with necessary methods', () => {
            const handlers = createSvelteKitHandlers()

            expect(handlers).toHaveProperty('status')
            expect(handlers).toHaveProperty('oauthStart')
            expect(handlers).toHaveProperty('oauthCallback')
            expect(handlers).toHaveProperty('logout')
        })

        it('should check connection status', async () => {
            const mockCookies = {
                get: jest.fn().mockReturnValue('test-token'),
            }

            const handlers = createSvelteKitHandlers()
            const response = await handlers.status({
                cookies: mockCookies as unknown as Cookies,
            })

            expect(mockCookies.get).toHaveBeenCalledWith('dropbox_access_token')
            expect(response.status).toBe(200)

            // Parse the response body
            const responseText = await response.text()
            const responseData = JSON.parse(responseText)
            expect(responseData).toEqual({ connected: true })
        })

        it('should start OAuth flow', async () => {
            const mockClient = {
                auth: {
                    getAuthUrl: jest
                        .fn()
                        .mockResolvedValue('https://dropbox.com/oauth'),
                },
            }

            ;(createDropboxSyncClient as jest.Mock).mockReturnValue(mockClient)

            const handlers = createSvelteKitHandlers()
            const response = await handlers.oauthStart()

            expect(createDropboxSyncClient).toHaveBeenCalled()
            expect(mockClient.auth.getAuthUrl).toHaveBeenCalled()
            expect(response.status).toBe(302)
            expect(response.headers.get('Location')).toBe(
                'https://dropbox.com/oauth'
            )
        })

        it('should handle OAuth callback success', async () => {
            const mockUrl = {
                searchParams: {
                    get: jest.fn().mockReturnValue('test-auth-code'),
                },
            } as unknown as URL

            const mockCookies = {
                set: jest.fn(),
            } as unknown as Cookies

            const mockClient = {
                auth: {
                    exchangeCodeForToken: jest.fn().mockResolvedValue({
                        accessToken: 'new-access-token',
                        refreshToken: 'new-refresh-token',
                        expiresAt: Date.now() + 14400 * 1000,
                    }),
                },
            }

            ;(createDropboxSyncClient as jest.Mock).mockReturnValue(mockClient)

            const handlers = createSvelteKitHandlers()
            const response = await handlers.oauthCallback({
                url: mockUrl,
                cookies: mockCookies,
            })

            expect(mockUrl.searchParams.get).toHaveBeenCalledWith('code')
            expect(createDropboxSyncClient).toHaveBeenCalled()
            expect(mockClient.auth.exchangeCodeForToken).toHaveBeenCalled()
            expect(mockCookies.set).toHaveBeenCalledTimes(3) // Access, refresh, and connected cookies
            expect(response.status).toBe(302)
            expect(response.headers.get('Location')).toBe('/')
        })

        it('should handle OAuth callback with missing code', async () => {
            const mockUrl = {
                searchParams: {
                    get: jest.fn().mockReturnValue(null),
                },
            } as unknown as URL

            const mockCookies = {} as unknown as Cookies

            const handlers = createSvelteKitHandlers()
            const response = await handlers.oauthCallback({
                url: mockUrl,
                cookies: mockCookies,
            })

            expect(mockUrl.searchParams.get).toHaveBeenCalledWith('code')
            expect(response.status).toBe(302)
            expect(response.headers.get('Location')).toBe('/auth/error')
        })

        it('should handle logout', async () => {
            const mockCookies = {
                delete: jest.fn(),
            } as unknown as Cookies

            const handlers = createSvelteKitHandlers()
            const response = await handlers.logout({ cookies: mockCookies })

            expect(mockCookies.delete).toHaveBeenCalledTimes(3) // Should delete three cookies
            expect(response.status).toBe(200)

            // Parse the response body
            const responseText = await response.text()
            const responseData = JSON.parse(responseText)
            expect(responseData).toEqual({ success: true })
        })
    })
})
