// Angular service implementation for Dropbox sync
import { Injectable } from '@angular/core'
import { BehaviorSubject, Observable, of, fromEvent } from 'rxjs'
import { catchError, map, tap } from 'rxjs/operators'
import { HttpClient } from '@angular/common/http'
// For a private module, you would import from your private registry or local path
// import { DropboxSyncService, getCredentialsFromEnvironment } from '@yourcompany/dropbox-sync';
import { DropboxSyncService, getCredentialsFromEnvironment } from 'dropbox-sync'
import { environment } from '../environments/environment'

@Injectable({
    providedIn: 'root',
})
export class DropboxService {
    // State observables
    private _connected = new BehaviorSubject<boolean>(false)
    private _syncing = new BehaviorSubject<boolean>(false)
    private _progress = new BehaviorSubject<number>(0)
    private _message = new BehaviorSubject<string>('')
    private _error = new BehaviorSubject<string | null>(null)

    // Public observable properties
    readonly connected$ = this._connected.asObservable()
    readonly syncing$ = this._syncing.asObservable()
    readonly progress$ = this._progress.asObservable()
    readonly message$ = this._message.asObservable()
    readonly error$ = this._error.asObservable()

    private syncStats = {
        total: 0,
        uploads: 0,
        downloads: 0,
        completed: 0,
    }

    constructor(
        private http: HttpClient,
        private dropboxSyncService: DropboxSyncService
    ) {
        // Initialize the Dropbox sync client
        this.initialize()
    }

    /**
     * Initialize the Dropbox sync client and check connection status
     */
    initialize(): void {
        // Get credentials from environment and localStorage
        const credentials = getCredentialsFromEnvironment(environment)

        // Initialize the service
        this.dropboxSyncService.initialize(credentials)

        // Check connection status
        this.checkConnection().subscribe()

        // Set up socket event listeners
        this.setupSocketEventListeners()
    }

    /**
     * Check if connected to Dropbox
     */
    checkConnection(): Observable<boolean> {
        return this.http
            .get<{ connected: boolean }>('/api/dropbox/status')
            .pipe(
                map((response) => response.connected),
                tap((connected) => this._connected.next(connected)),
                catchError((error) => {
                    console.error('Error checking Dropbox connection:', error)
                    this._connected.next(false)
                    return of(false)
                })
            )
    }

    /**
     * Start the OAuth flow to connect to Dropbox
     */
    connect(): void {
        window.location.href = '/api/dropbox/auth/start'
    }

    /**
     * Disconnect from Dropbox
     */
    disconnect(): Observable<boolean> {
        return this.http
            .post<{ success: boolean }>('/api/dropbox/logout', {})
            .pipe(
                tap((response) => {
                    if (response.success) {
                        this._connected.next(false)
                        localStorage.removeItem('dropbox_access_token')
                        localStorage.removeItem('dropbox_refresh_token')
                        localStorage.removeItem('dropbox_connected')
                    }
                }),
                map((response) => response.success),
                catchError((error) => {
                    console.error('Error disconnecting from Dropbox:', error)
                    return of(false)
                })
            )
    }

    /**
     * Start syncing files with Dropbox
     */
    startSync(options?: { localDir?: string; dropboxDir?: string }): void {
        try {
            // Reset state
            this._syncing.next(true)
            this._progress.next(0)
            this._message.next('Initializing Dropbox sync...')
            this._error.next(null)

            // Get socket from the sync service and emit sync event
            const client = this.dropboxSyncService.getClient()
            client.socket.connect()
            client.socket.emit('dropbox:sync', options)
        } catch (error: any) {
            console.error('Error starting Dropbox sync:', error)
            this._error.next(error.message || 'Error starting synchronization')
            this._syncing.next(false)
        }
    }

    /**
     * Cancel ongoing sync process
     */
    cancelSync(): void {
        try {
            const client = this.dropboxSyncService.getClient()
            client.sync.cancelSync()
            this._syncing.next(false)
            this._message.next('Sync cancelled by user')
        } catch (error: any) {
            console.error('Error cancelling sync:', error)
        }
    }

    /**
     * Check which files need to be synced without performing sync
     */
    checkSyncNeeded(options?: {
        localDir?: string
        dropboxDir?: string
    }): Observable<{ upload: number; download: number }> {
        try {
            const client = this.dropboxSyncService.getClient()

            return this.dropboxSyncService.createSyncQueue(options).pipe(
                map(({ uploadQueue, downloadQueue }) => ({
                    upload: uploadQueue.length,
                    download: downloadQueue.length,
                })),
                catchError((error) => {
                    console.error('Error checking sync status:', error)
                    return of({ upload: 0, download: 0 })
                })
            )
        } catch (error) {
            console.error('Error creating sync queue:', error)
            return of({ upload: 0, download: 0 })
        }
    }

    /**
     * Set up socket event listeners for real-time sync updates
     */
    private setupSocketEventListeners(): void {
        try {
            const client = this.dropboxSyncService.getClient()
            const socketProgress =
                this.dropboxSyncService.setupSocketListeners()

            // Subscribe to the socket events observable
            socketProgress.subscribe({
                next: (data: any) => {
                    switch (data.type) {
                        case 'progress':
                            this._progress.next(data.data.progress)
                            this._message.next(data.data.message)
                            break

                        case 'queue':
                            this.syncStats = {
                                total: data.data.total,
                                uploads: data.data.totalUploads,
                                downloads: data.data.totalDownloads,
                                completed: 0,
                            }
                            break

                        case 'complete':
                            this._progress.next(100)
                            this._message.next(data.data.message)
                            this._syncing.next(false)

                            if (data.data.stats) {
                                this.syncStats.completed = this.syncStats.total
                            }
                            break

                        case 'error':
                            this._error.next(data.data.message)
                            if (!data.data.continue) {
                                this._syncing.next(false)
                            }
                            break
                    }
                },
                error: (error) => {
                    this._error.next(
                        typeof error === 'string'
                            ? error
                            : 'An error occurred during synchronization'
                    )
                    this._syncing.next(false)
                },
                complete: () => {
                    // Sync process completed successfully
                    console.log('Dropbox sync process completed')
                },
            })
        } catch (error) {
            console.error('Error setting up socket listeners:', error)
        }
    }

    /**
     * Get current sync statistics
     */
    getSyncStats(): {
        total: number
        uploads: number
        downloads: number
        completed: number
    } {
        return { ...this.syncStats }
    }
}
