import SwiftUI

/// Settings screen for choosing which languages voice notes can be transcribed
/// in. Enabling a language reserves it and downloads its on-device model; the
/// system caps how many can be reserved at once, so the list disables further
/// toggles at capacity and explains the limit in the footer.
struct TranscriptionLanguagesView: View {
    @Environment(TranscriptionSettings.self) private var settings
    @State private var errorMessage: String?

    var body: some View {
        List {
            if let errorMessage {
                Section {
                    Label(errorMessage, systemImage: "exclamationmark.triangle")
                        .font(.footnote)
                        .foregroundStyle(.red)
                }
            }

            if !enabledLocales.isEmpty {
                Section("Enabled") {
                    ForEach(enabledLocales, id: \.identifier) { row($0) }
                }
            }

            Section {
                ForEach(otherLocales, id: \.identifier) { row($0) }
            } header: {
                Text("All Languages")
            } footer: {
                Text(footerText)
            }
        }
        .navigationTitle("Languages")
        .overlay {
            if settings.supportedLocales.isEmpty {
                ProgressView()
            }
        }
        .task { await settings.prepare() }
    }

    private var enabledLocales: [Locale] {
        settings.supportedLocales.filter { settings.isEnabled($0) }
    }

    private var otherLocales: [Locale] {
        settings.supportedLocales.filter { !settings.isEnabled($0) }
    }

    private var footerText: String {
        guard settings.maximumReserved > 0 else {
            return "Each new note is transcribed on device in your enabled languages."
        }
        return "Enable up to \(settings.maximumReserved) languages. Each new voice note is sampled in your enabled languages and transcribed in whichever fits best."
    }

    private func row(_ locale: Locale) -> some View {
        let enabled = settings.isEnabled(locale)
        return HStack {
            VStack(alignment: .leading, spacing: 2) {
                Text(TranscriptionSettings.displayName(for: locale))
                stateSubtitle(for: locale)
            }
            Spacer()
            Toggle("", isOn: Binding(
                get: { settings.isEnabled(locale) },
                set: { toggle(locale, on: $0) }
            ))
            .labelsHidden()
            .disabled(!enabled && settings.isAtCapacity)
        }
    }

    @ViewBuilder
    private func stateSubtitle(for locale: Locale) -> some View {
        switch settings.assetStates[TranscriptionSettings.canonicalID(locale)] {
        case .installed:
            Label("Installed", systemImage: "checkmark.circle.fill")
                .font(.caption)
                .foregroundStyle(.green)
        case .downloading(let fraction):
            HStack(spacing: 6) {
                ProgressView().controlSize(.small)
                if let fraction {
                    Text("Downloading \(Int(fraction * 100))%")
                } else {
                    Text("Downloading…")
                }
            }
            .font(.caption)
            .foregroundStyle(.secondary)
        case .notInstalled:
            Label("Available to download", systemImage: "icloud.and.arrow.down")
                .font(.caption)
                .foregroundStyle(.secondary)
        case .unsupported, .none:
            EmptyView()
        }
    }

    private func toggle(_ locale: Locale, on: Bool) {
        errorMessage = nil
        Task {
            if on {
                do {
                    try await settings.enable(locale)
                } catch TranscriptionSettings.SettingsError.atCapacity {
                    errorMessage = "You can enable up to \(settings.maximumReserved) languages. Turn one off first."
                } catch {
                    errorMessage = "Couldn't enable \(TranscriptionSettings.displayName(for: locale)): \(error.localizedDescription)"
                }
            } else {
                await settings.disable(locale)
            }
        }
    }
}
