//
//  iCloudSettingsView.swift
//  Yattee
//
//  Settings for iCloud sync configuration.
//

import CloudKit
import SwiftUI

struct iCloudSettingsView: View {
    @Environment(\.appEnvironment) private var appEnvironment
    @State private var showingEnableConfirmation = false
    @State private var showingDisableConfirmation = false
    @State private var showingCategoryEnableConfirmation: SyncCategory?
    @State private var showingCategorySyncConfirmation: SyncCategory?
    @State private var lastManualSyncTime: Date?
    @State private var expandedError = false
    @State private var expandedUpdateWarning = false
    @State private var syncRotation: Double = 0

    private var settingsManager: SettingsManager? {
        appEnvironment?.settingsManager
    }

    private var instancesManager: InstancesManager? {
        appEnvironment?.instancesManager
    }

    private var cloudKitSync: CloudKitSyncEngine? {
        appEnvironment?.cloudKitSync
    }

    private var mediaSourcesManager: MediaSourcesManager? {
        appEnvironment?.mediaSourcesManager
    }

    private var lastManualSyncRelative: String? {
        guard let lastSync = lastManualSyncTime else { return nil }
        return RelativeDateFormatter.string(for: lastSync, unitsStyle: .full)
    }

    private var syncNowIcon: String {
        if #available(iOS 18.0, macOS 15.0, tvOS 18.0, *) {
            return "arrow.trianglehead.2.clockwise.rotate.90.icloud"
        } else {
            return "bolt.horizontal.icloud"
        }
    }

    var body: some View {
        SettingsFormContainer {
            #if DEBUG
            SettingsFormSection(footer: "settings.icloud.dev.footer") {
                Label(String(localized: "settings.icloud.dev.title"), systemImage: "hammer.fill")
                    .foregroundStyle(.orange)
                    .font(.subheadline)
            }
            #endif

            if cloudKitSync?.isCloudKitAvailable == false {
                SettingsFormSection(footer: "settings.icloud.unavailable.footer") {
                    Label(String(localized: "settings.icloud.unavailable"), systemImage: "icloud.slash")
                        .foregroundStyle(.secondary)
                }
            } else {
                SettingsFormSection(footer: "settings.icloud.footer") {
                    Toggle(isOn: Binding(
                        get: { settingsManager?.iCloudSyncEnabled ?? false },
                        set: { newValue in
                            if newValue {
                                showingEnableConfirmation = true
                            } else {
                                showingDisableConfirmation = true
                            }
                        }
                    )) {
                        Label(String(localized: "settings.icloud.enable"), systemImage: "icloud")
                    }
                }

                if settingsManager?.iCloudSyncEnabled == true {
                    syncCategoriesSection
                    syncStatusSection
                }
            }
        }
        #if !os(tvOS)
        .navigationTitle(String(localized: "settings.icloud.title"))
        #endif
        #if os(iOS)
        .navigationBarTitleDisplayMode(.inline)
        #endif
        .task {
            await cloudKitSync?.refreshAccountStatus()
        }
        .confirmationDialog(
            String(localized: "settings.icloud.enable.confirmation.title"),
            isPresented: $showingEnableConfirmation,
            titleVisibility: .visible
        ) {
            Button(String(localized: "settings.icloud.enable.confirmation.action"), role: .destructive) {
                enableiCloudSync()
            }
            Button(String(localized: "common.cancel"), role: .cancel) {}
        } message: {
            Text(String(localized: "settings.icloud.enable.confirmation.message"))
        }
        .presentationCompactAdaptation(.sheet)
        .confirmationDialog(
            String(localized: "settings.icloud.disable.confirmation.title"),
            isPresented: $showingDisableConfirmation,
            titleVisibility: .visible
        ) {
            Button(String(localized: "settings.icloud.disable.confirmation.action"), role: .destructive) {
                disableiCloudSync()
            }
            Button(String(localized: "common.cancel"), role: .cancel) {}
        } message: {
            Text(String(localized: "settings.icloud.disable.confirmation.message"))
        }
        .presentationCompactAdaptation(.sheet)
        // Confirmation for categories that replace local data (instances, settings, media sources)
        .confirmationDialog(
            String(localized: "settings.icloud.category.enable.title"),
            isPresented: .init(
                get: { showingCategoryEnableConfirmation != nil },
                set: { if !$0 { showingCategoryEnableConfirmation = nil } }
            ),
            titleVisibility: .visible
        ) {
            Button(String(localized: "settings.icloud.category.enable.action"), role: .destructive) {
                if let category = showingCategoryEnableConfirmation {
                    enableCategory(category)
                }
                showingCategoryEnableConfirmation = nil
            }
            Button(String(localized: "common.cancel"), role: .cancel) {
                showingCategoryEnableConfirmation = nil
            }
        } message: {
            Text(String(localized: "settings.icloud.category.enable.message"))
        }
        .presentationCompactAdaptation(.sheet)
        // Confirmation for categories that upload/merge local data (subscriptions, bookmarks, playlists, history)
        .confirmationDialog(
            String(localized: "settings.icloud.category.sync.title"),
            isPresented: .init(
                get: { showingCategorySyncConfirmation != nil },
                set: { if !$0 { showingCategorySyncConfirmation = nil } }
            ),
            titleVisibility: .visible
        ) {
            Button(String(localized: "settings.icloud.category.sync.action")) {
                if let category = showingCategorySyncConfirmation {
                    enableCategory(category)
                }
                showingCategorySyncConfirmation = nil
            }
            Button(String(localized: "common.cancel"), role: .cancel) {
                showingCategorySyncConfirmation = nil
            }
        } message: {
            Text(String(localized: "settings.icloud.category.sync.message"))
        }
        .presentationCompactAdaptation(.sheet)
    }

    // MARK: - Sync Categories Section

    @ViewBuilder
    private var syncCategoriesSection: some View {
        SettingsFormSection(footer: "settings.icloud.categories.footer") {
            Toggle(isOn: Binding(
                get: { settingsManager?.syncInstances ?? true },
                set: { newValue in
                    if newValue {
                        showCategoryConfirmation(for: .instances)
                    } else {
                        settingsManager?.syncInstances = false
                    }
                }
            )) {
                Label(String(localized: "settings.icloud.category.instances"), systemImage: "server.rack")
            }

            Toggle(isOn: Binding(
                get: { settingsManager?.syncSubscriptions ?? true },
                set: { newValue in
                    if newValue {
                        showCategoryConfirmation(for: .subscriptions)
                    } else {
                        settingsManager?.syncSubscriptions = false
                    }
                }
            )) {
                Label(String(localized: "settings.icloud.category.subscriptions"), systemImage: "person.2")
            }

            Toggle(isOn: Binding(
                get: { settingsManager?.syncBookmarks ?? true },
                set: { newValue in
                    if newValue {
                        showCategoryConfirmation(for: .bookmarks)
                    } else {
                        settingsManager?.syncBookmarks = false
                    }
                }
            )) {
                Label(String(localized: "settings.icloud.category.bookmarks"), systemImage: "bookmark.fill")
            }

            Toggle(isOn: Binding(
                get: { settingsManager?.syncPlaylists ?? true },
                set: { newValue in
                    if newValue {
                        showCategoryConfirmation(for: .playlists)
                    } else {
                        settingsManager?.syncPlaylists = false
                    }
                }
            )) {
                Label(String(localized: "settings.icloud.category.playlists"), systemImage: "list.bullet.rectangle")
            }

            Toggle(isOn: Binding(
                get: { settingsManager?.syncPlaybackHistory ?? true },
                set: { newValue in
                    if newValue {
                        showCategoryConfirmation(for: .playbackHistory)
                    } else {
                        settingsManager?.syncPlaybackHistory = false
                    }
                }
            )) {
                Label(String(localized: "settings.icloud.category.playbackHistory"), systemImage: "clock.arrow.circlepath")
            }

            Toggle(isOn: Binding(
                get: { settingsManager?.syncSearchHistory ?? true },
                set: { newValue in
                    if newValue {
                        showCategoryConfirmation(for: .searchHistory)
                    } else {
                        settingsManager?.syncSearchHistory = false
                    }
                }
            )) {
                Label(String(localized: "settings.icloud.category.searchHistory"), systemImage: "magnifyingglass.circle")
            }

            Toggle(isOn: Binding(
                get: { settingsManager?.syncSettings ?? true },
                set: { newValue in
                    if newValue {
                        showCategoryConfirmation(for: .settings)
                    } else {
                        settingsManager?.syncSettings = false
                    }
                }
            )) {
                Label(String(localized: "settings.icloud.category.settings"), systemImage: "gearshape")
            }

            Toggle(isOn: Binding(
                get: { settingsManager?.syncMediaSources ?? true },
                set: { newValue in
                    if newValue {
                        showCategoryConfirmation(for: .mediaSources)
                    } else {
                        settingsManager?.syncMediaSources = false
                    }
                }
            )) {
                Label(String(localized: "settings.icloud.category.mediaSources"), systemImage: "externaldrive.connected.to.line.below")
            }
        }
        #if os(macOS)
        .labelStyle(FixedIconWidthLabelStyle())
        #endif
    }

    // MARK: - Sync Status Section

    @ViewBuilder
    private var syncStatusSection: some View {
        let footer: LocalizedStringKey? = lastManualSyncRelative.map { LocalizedStringKey("settings.icloud.lastManualSync \($0)") }
        SettingsFormSection(footer: footer) {
            // iCloud Account Status
            HStack {
                Label(String(localized: "settings.icloud.account"), systemImage: "person.crop.circle")
                Spacer()
                HStack(spacing: 6) {
                    accountStatusIcon
                    Text(cloudKitSync?.accountStatusText ?? "Unknown")
                        .foregroundStyle(.secondary)
                }
            }
            
            // Sync Status
            HStack {
                Label(String(localized: "settings.icloud.status"), systemImage: "arrow.triangle.2.circlepath")
                Spacer()
                HStack(spacing: 6) {
                    syncStatusIcon
                    Text(cloudKitSync?.syncStatusText ?? "Unknown")
                        .foregroundStyle(.secondary)
                }
            }
            
            // Pending Changes (if any)
            if let count = cloudKitSync?.pendingChangesCount, count > 0 {
                HStack {
                    Label(String(localized: "settings.icloud.pending"), systemImage: "clock")
                    Spacer()
                    Text(verbatim: "\(count) item\(count == 1 ? "" : "s")")
                        .foregroundStyle(.secondary)
                }
            }
            
            // Last Sync (automatic)
            if let lastSync = cloudKitSync?.lastSyncDate {
                HStack {
                    Label(String(localized: "settings.icloud.lastSynced"), systemImage: "checkmark.circle")
                    Spacer()
                    Text(lastSync, style: .relative)
                        .foregroundStyle(.secondary)
                }
            }
            
            // Error Row (expandable)
            if case .error(let error) = cloudKitSync?.syncStatus {
                errorRow(error)
            }

            // Update available warning (newer schema detected)
            if cloudKitSync?.hasNewerSchemaRecords == true {
                updateAvailableRow
            }

            // Upload Progress (initial sync)
            if let progress = cloudKitSync?.uploadProgress {
                VStack(alignment: .leading, spacing: 8) {
                    HStack {
                        if !progress.isComplete {
                            ProgressView()
                                .controlSize(.small)
                        } else {
                            Image(systemName: "checkmark.circle.fill")
                                .foregroundStyle(.green)
                        }
                        Text(progress.displayText)
                            .foregroundStyle(.secondary)
                    }
                }
            }
            
            // Sync Now Button
            Button {
                syncNow()
            } label: {
                Label(String(localized: "settings.icloud.syncNow"), systemImage: syncNowIcon)
            }
            .disabled(cloudKitSync?.isSyncing == true)
        }
        .animation(.easeInOut(duration: 0.3), value: cloudKitSync?.syncStatus)
        .animation(.easeInOut(duration: 0.3), value: cloudKitSync?.uploadProgress)
    }

    // MARK: - Status Icons
    
    private var accountStatusIcon: some View {
        Group {
            switch cloudKitSync?.accountStatus {
            case .available:
                Image(systemName: "checkmark.circle.fill")
                    .foregroundStyle(.green)
            case .noAccount, .restricted:
                Image(systemName: "exclamationmark.triangle.fill")
                    .foregroundStyle(.orange)
            case .temporarilyUnavailable:
                Image(systemName: "exclamationmark.circle.fill")
                    .foregroundStyle(.yellow)
            default:
                Image(systemName: "questionmark.circle.fill")
                    .foregroundStyle(.gray)
            }
        }
    }
    
    private var syncStatusIcon: some View {
        Group {
            // Show rotating icon for both syncing and receiving changes
            if cloudKitSync?.isSyncing == true || cloudKitSync?.isReceivingChanges == true {
                Image(systemName: "arrow.triangle.2.circlepath")
                    .foregroundStyle(.blue)
                    .rotationEffect(.degrees(syncRotation))
                    .onAppear {
                        withAnimation(.linear(duration: 1.5).repeatForever(autoreverses: false)) {
                            syncRotation = 360
                        }
                    }
                    .onDisappear {
                        syncRotation = 0
                    }
            } else {
                switch cloudKitSync?.syncStatus {
                case .syncing:
                    // Handled above
                    EmptyView()
                case .upToDate:
                    Image(systemName: "checkmark.circle.fill")
                        .foregroundStyle(.green)
                case .pending:
                    Image(systemName: "clock.fill")
                        .foregroundStyle(.orange)
                case .error:
                    Image(systemName: "exclamationmark.circle.fill")
                        .foregroundStyle(.red)
                case .none:
                    Image(systemName: "questionmark.circle.fill")
                        .foregroundStyle(.gray)
                }
            }
        }
    }
    
    // MARK: - Error Display
    
    @ViewBuilder
    private func errorRow(_ error: Error) -> some View {
        VStack(alignment: .leading, spacing: 8) {
            // Collapsed view
            Button {
                withAnimation {
                    expandedError.toggle()
                }
            } label: {
                HStack {
                    Image(systemName: "exclamationmark.circle.fill")
                        .foregroundStyle(.red)
                    Text(String(localized: "settings.icloud.syncError"))
                        .foregroundStyle(.primary)
                    Spacer()
                    Image(systemName: expandedError ? "chevron.up" : "chevron.down")
                        .foregroundStyle(.secondary)
                        .font(.caption)
                }
            }
            
            // Expanded view with details
            if expandedError {
                VStack(alignment: .leading, spacing: 8) {
                    Text(error.localizedDescription)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                        .fixedSize(horizontal: false, vertical: true)
                    
                    // Retry button
                    Button {
                        Task {
                            await cloudKitSync?.sync()
                        }
                    } label: {
                        Label(String(localized: "settings.icloud.retrySync"), systemImage: "arrow.clockwise")
                            .font(.caption)
                    }
                    .buttonStyle(.bordered)
                    .controlSize(.small)
                }
                .padding(.leading, 28) // Align with text
            }
        }
    }

    @ViewBuilder
    private var updateAvailableRow: some View {
        VStack(alignment: .leading, spacing: 8) {
            Button {
                withAnimation {
                    expandedUpdateWarning.toggle()
                }
            } label: {
                HStack {
                    Image(systemName: "arrow.up.circle.fill")
                        .foregroundStyle(.orange)
                    Text(String(localized: "settings.icloud.update.title"))
                        .foregroundStyle(.primary)
                    Spacer()
                    Image(systemName: expandedUpdateWarning ? "chevron.up" : "chevron.down")
                        .foregroundStyle(.secondary)
                        .font(.caption)
                }
            }

            if expandedUpdateWarning {
                Text(String(localized: "settings.icloud.update.message"))
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .fixedSize(horizontal: false, vertical: true)
                    .padding(.leading, 28)
            }
        }
    }

    // MARK: - Actions

    private func showCategoryConfirmation(for category: SyncCategory) {
        if category.usesReplaceStrategy {
            showingCategoryEnableConfirmation = category
        } else {
            showingCategorySyncConfirmation = category
        }
    }

    private func enableiCloudSync() {
        // Enable sync setting and all categories by default
        settingsManager?.iCloudSyncEnabled = true
        settingsManager?.enableAllSyncCategories()

        // Enable CloudKit sync engine then upload all existing local data
        Task {
            await cloudKitSync?.enable()
            await cloudKitSync?.performInitialUpload()
        }

        // Keep old sync for non-migrated data
        settingsManager?.replaceWithiCloudData()
        instancesManager?.replaceWithiCloudData()
        mediaSourcesManager?.replaceWithiCloudData()
    }

    private func disableiCloudSync() {
        settingsManager?.iCloudSyncEnabled = false
        cloudKitSync?.disable()
    }

    private func enableCategory(_ category: SyncCategory) {
        switch category {
        case .instances:
            settingsManager?.syncInstances = true
            instancesManager?.replaceWithiCloudData()
        case .subscriptions:
            settingsManager?.syncSubscriptions = true
            // Upload existing subscriptions to CloudKit
            Task {
                await cloudKitSync?.uploadAllLocalSubscriptions()
            }
        case .playbackHistory:
            settingsManager?.syncPlaybackHistory = true
            // Upload existing watch history to CloudKit
            Task {
                await cloudKitSync?.uploadAllLocalWatchHistory()
            }
        case .bookmarks:
            settingsManager?.syncBookmarks = true
            // Upload existing bookmarks to CloudKit
            Task {
                await cloudKitSync?.uploadAllLocalBookmarks()
            }
        case .playlists:
            settingsManager?.syncPlaylists = true
            // Upload existing playlists to CloudKit
            Task {
                await cloudKitSync?.uploadAllLocalPlaylists()
            }
        case .searchHistory:
            settingsManager?.syncSearchHistory = true
            // Upload existing search history to CloudKit
            Task {
                await cloudKitSync?.uploadAllLocalSearchHistory()
                await cloudKitSync?.uploadAllRecentChannels()
                await cloudKitSync?.uploadAllRecentPlaylists()
            }
        case .settings:
            settingsManager?.syncSettings = true
            settingsManager?.replaceWithiCloudData()
            // Upload existing controls presets to CloudKit
            Task {
                await cloudKitSync?.uploadAllLocalControlsPresets()
            }
        case .mediaSources:
            settingsManager?.syncMediaSources = true
            mediaSourcesManager?.replaceWithiCloudData()
        }
    }

    private func syncNow() {
        // Trigger CloudKit refresh sync (clears stale tokens, fetches all changes)
        Task {
            await cloudKitSync?.refreshSync()
        }
        
        // Push other data to iCloud (non-CloudKit)
        settingsManager?.syncToiCloud()
        instancesManager?.syncToiCloud()
        mediaSourcesManager?.syncToiCloud()
        lastManualSyncTime = Date()
    }
}

// MARK: - Sync Category

private enum SyncCategory {
    case instances
    case subscriptions
    case bookmarks
    case playbackHistory
    case playlists
    case searchHistory
    case mediaSources
    case settings
    

    /// Categories that replace local data with iCloud data
    var usesReplaceStrategy: Bool {
        switch self {
        case .instances, .settings, .mediaSources:
            return true
        case .subscriptions, .bookmarks, .playlists, .playbackHistory, .searchHistory:
            return false
        }
    }
}

// MARK: - Preview

#Preview {
    NavigationStack {
        iCloudSettingsView()
    }
    .appEnvironment(.preview)
}
