// fe/src/composables/useConflictResolution.ts
// Unified conflict resolution system for optimistic updates

import { ref, computed } from 'vue'
import type { ConflictResolution, OptimisticUpdate } from '@/types/shared'

interface ConflictState {
    pendingConflicts: Map<string, ConflictResolution<any>>
    optimisticUpdates: Map<string, OptimisticUpdate<any>>
    resolutionStrategies: Map<string, 'local' | 'server' | 'merge' | 'manual'>
}

const state = ref<ConflictState>({
    pendingConflicts: new Map(),
    optimisticUpdates: new Map(),
    resolutionStrategies: new Map()
})

export function useConflictResolution() {

    // Computed properties
    const hasConflicts = computed(() => state.value.pendingConflicts.size > 0)
    const conflictCount = computed(() => state.value.pendingConflicts.size)
    const pendingUpdates = computed(() => state.value.optimisticUpdates.size)

    // Track an optimistic update
    function trackOptimisticUpdate<T>(
        entityType: string,
        entityId: number,
        operation: 'create' | 'update' | 'delete',
        data: T
    ): string {
        const updateId = `${entityType}_${entityId}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`

        const update: OptimisticUpdate<T> = {
            id: updateId,
            entity_type: entityType,
            entity_id: entityId,
            operation,
            data,
            timestamp: new Date().toISOString(),
            status: 'pending'
        }

        state.value.optimisticUpdates.set(updateId, update)
        console.log('[ConflictResolution] Tracked optimistic update:', updateId)

        return updateId
    }

    // Confirm an optimistic update succeeded
    function confirmOptimisticUpdate(updateId: string, serverData?: any) {
        const update = state.value.optimisticUpdates.get(updateId)
        if (update) {
            update.status = 'confirmed'
            if (serverData) {
                update.data = serverData
            }
            // Keep confirmed updates for a short time for debugging
            setTimeout(() => {
                state.value.optimisticUpdates.delete(updateId)
            }, 5000)

            console.log('[ConflictResolution] Confirmed optimistic update:', updateId)
        }
    }

    // Mark an optimistic update as failed and create conflict if needed
    function failOptimisticUpdate<T>(
        updateId: string,
        serverData: T,
        serverVersion: number
    ): string | null {
        const update = state.value.optimisticUpdates.get(updateId)
        if (!update) return null

        update.status = 'failed'

        // Create conflict resolution entry
        const conflictId = `conflict_${updateId}`
        const conflict: ConflictResolution<T> = {
            id: conflictId,
            entity_type: update.entity_type,
            entity_id: update.entity_id,
            local_version: 0, // We don't track versions in optimistic updates
            server_version: serverVersion,
            local_data: update.data,
            server_data: serverData,
            resolution_strategy: getDefaultStrategy(update.entity_type)
        }

        state.value.pendingConflicts.set(conflictId, conflict)
        console.log('[ConflictResolution] Created conflict:', conflictId)

        return conflictId
    }

    // Get default resolution strategy for entity type
    function getDefaultStrategy(entityType: string): 'local' | 'server' | 'merge' | 'manual' {
        const strategies = state.value.resolutionStrategies.get(entityType)
        if (strategies) return strategies

        // Default strategies by entity type
        switch (entityType) {
            case 'expense':
            case 'settlement':
                return 'manual' // Financial data requires manual review
            case 'chore':
                return 'server' // Prefer server state for chores
            case 'list':
            case 'item':
                return 'merge' // Try to merge list changes
            default:
                return 'server'
        }
    }

    // Set resolution strategy for entity type
    function setResolutionStrategy(entityType: string, strategy: 'local' | 'server' | 'merge' | 'manual') {
        state.value.resolutionStrategies.set(entityType, strategy)
    }

    // Resolve a conflict with chosen strategy
    function resolveConflict<T>(
        conflictId: string,
        strategy: 'local' | 'server' | 'merge' | 'manual',
        mergedData?: T
    ): T | null {
        const conflict = state.value.pendingConflicts.get(conflictId)
        if (!conflict) return null

        let resolvedData: T

        switch (strategy) {
            case 'local':
                resolvedData = conflict.local_data
                break
            case 'server':
                resolvedData = conflict.server_data
                break
            case 'merge':
                resolvedData = mergeData(conflict.local_data, conflict.server_data)
                break
            case 'manual':
                if (!mergedData) {
                    console.error('[ConflictResolution] Manual resolution requires merged data')
                    return null
                }
                resolvedData = mergedData
                break
        }

        // Update conflict with resolution
        conflict.resolution_strategy = strategy
        conflict.resolved_data = resolvedData
        conflict.resolved_at = new Date().toISOString()

        // Remove from pending conflicts
        state.value.pendingConflicts.delete(conflictId)

        console.log('[ConflictResolution] Resolved conflict:', conflictId, 'with strategy:', strategy)
        return resolvedData
    }

    // Smart merge algorithm for common data types
    function mergeData<T>(localData: T, serverData: T): T {
        if (typeof localData !== 'object' || typeof serverData !== 'object') {
            return serverData // Fallback to server data for primitives
        }

        // For objects, merge non-conflicting properties
        const merged = { ...serverData } as any
        const local = localData as any
        const server = serverData as any

        for (const key in local) {
            if (local.hasOwnProperty(key)) {
                // Prefer local changes for certain fields
                if (isUserEditableField(key)) {
                    merged[key] = local[key]
                }
                // For arrays, try to merge intelligently
                else if (Array.isArray(local[key]) && Array.isArray(server[key])) {
                    merged[key] = mergeArrays(local[key], server[key])
                }
                // For dates, prefer the more recent one
                else if (isDateField(key)) {
                    const localDate = new Date(local[key])
                    const serverDate = new Date(server[key])
                    merged[key] = localDate > serverDate ? local[key] : server[key]
                }
            }
        }

        return merged as T
    }

    // Check if field is typically user-editable
    function isUserEditableField(fieldName: string): boolean {
        const editableFields = [
            'name', 'description', 'notes', 'title',
            'quantity', 'price', 'category',
            'priority', 'status',
            'custom_interval_days'
        ]
        return editableFields.includes(fieldName)
    }

    // Check if field represents a date
    function isDateField(fieldName: string): boolean {
        return fieldName.includes('_at') || fieldName.includes('date') || fieldName.includes('time')
    }

    // Merge arrays intelligently (basic implementation)
    function mergeArrays<T>(localArray: T[], serverArray: T[]): T[] {
        // Simple merge - combine arrays and remove duplicates based on id
        const merged = [...serverArray]

        localArray.forEach(localItem => {
            const localItemAny = localItem as any
            if (localItemAny.id) {
                const existingIndex = merged.findIndex((item: any) => item.id === localItemAny.id)
                if (existingIndex >= 0) {
                    // Replace with local version
                    merged[existingIndex] = localItem
                } else {
                    // Add new local item
                    merged.push(localItem)
                }
            } else {
                // No ID, just add if not duplicate
                if (!merged.some(item => JSON.stringify(item) === JSON.stringify(localItem))) {
                    merged.push(localItem)
                }
            }
        })

        return merged
    }

    // Get all pending conflicts
    function getPendingConflicts() {
        return Array.from(state.value.pendingConflicts.values())
    }

    // Get specific conflict
    function getConflict(conflictId: string) {
        return state.value.pendingConflicts.get(conflictId)
    }

    // Clear all conflicts (for testing or reset)
    function clearConflicts() {
        state.value.pendingConflicts.clear()
        state.value.optimisticUpdates.clear()
    }

    // Get statistics
    function getStats() {
        return {
            pendingConflicts: state.value.pendingConflicts.size,
            optimisticUpdates: state.value.optimisticUpdates.size,
            confirmedUpdates: Array.from(state.value.optimisticUpdates.values())
                .filter(u => u.status === 'confirmed').length,
            failedUpdates: Array.from(state.value.optimisticUpdates.values())
                .filter(u => u.status === 'failed').length
        }
    }

    return {
        // State
        hasConflicts,
        conflictCount,
        pendingUpdates,

        // Methods
        trackOptimisticUpdate,
        confirmOptimisticUpdate,
        failOptimisticUpdate,
        resolveConflict,
        setResolutionStrategy,
        getPendingConflicts,
        getConflict,
        clearConflicts,
        getStats
    }
} 