import SwiftUI
import PhotosUI
import CoreLocation

struct AddDiaryEntrySheet: View {
    let dogId: Int
    let onSaved: () async -> Void

    @Environment(\.dismiss) private var dismiss

    @State private var titel = ""
    @State private var text = ""
    @State private var date = Date()
    @State private var isMilestone = false
    @State private var locationName = ""
    @State private var tagsInput = ""

    @State private var photoSelection: [PhotosPickerItem] = []
    @State private var photoData: [Data] = []

    @State private var location = OneShotLocation()
    @State private var attachLocation = true
    @State private var isReverseGeocoding = false

    @State private var saveState: SaveState = .idle
    @State private var errorMessage: String?

    private enum SaveState: Equatable {
        case idle
        case savingEntry
        case uploadingMedia(done: Int, total: Int)
    }

    var body: some View {
        NavigationStack {
            Form {
                Section("Titel") {
                    TextField("z. B. Erster Strandbesuch", text: $titel)
                }
                Section("Text") {
                    TextField("Was hat dein Hund heute erlebt?", text: $text, axis: .vertical)
                        .lineLimit(4...10)
                }
                Section("Datum") {
                    DatePicker("Datum", selection: $date, displayedComponents: .date)
                        .environment(\.locale, Locale(identifier: "de_DE"))
                }
                Section {
                    Toggle("Meilenstein", isOn: $isMilestone)
                    TextField("Tags (komma-getrennt)", text: $tagsInput)
                        .textInputAutocapitalization(.never)
                        .autocorrectionDisabled()
                }

                Section {
                    Toggle(isOn: $attachLocation) {
                        Label("Standort verwenden", systemImage: "location.fill")
                    }
                    if attachLocation {
                        if let coord = location.coordinate {
                            HStack {
                                Image(systemName: "mappin.and.ellipse")
                                    .foregroundStyle(Color.accentColor)
                                VStack(alignment: .leading, spacing: 2) {
                                    if !locationName.isEmpty {
                                        Text(locationName).font(.subheadline)
                                    } else if isReverseGeocoding {
                                        Text("Suche Ortsbezeichnung…")
                                            .font(.caption)
                                            .foregroundStyle(.secondary)
                                    } else {
                                        Text("Ort wird mitgespeichert")
                                            .font(.subheadline)
                                    }
                                    Text(String(format: "%.5f, %.5f", coord.latitude, coord.longitude))
                                        .font(.caption2.monospacedDigit())
                                        .foregroundStyle(.tertiary)
                                }
                            }
                        } else if location.error != nil {
                            Label("Standort nicht verfügbar — wird ohne gespeichert", systemImage: "location.slash")
                                .font(.caption)
                                .foregroundStyle(.secondary)
                        } else {
                            HStack {
                                ProgressView()
                                Text("Hole Standort…").font(.caption).foregroundStyle(.secondary)
                            }
                        }
                        TextField("Ort überschreiben (optional)", text: $locationName)
                    }
                } header: {
                    Text("Standort")
                } footer: {
                    Text("Der Standort wird zusammen mit dem Eintrag gespeichert — banyaro.app rendert daraus deine POI-Karte.")
                        .font(.caption2)
                }

                Section {
                    PhotosPicker(
                        selection: $photoSelection,
                        maxSelectionCount: 6,
                        matching: .images
                    ) {
                        Label(photoData.isEmpty ? "Fotos hinzufügen" : "Fotos ändern", systemImage: "photo.badge.plus")
                    }
                    if !photoData.isEmpty {
                        ScrollView(.horizontal, showsIndicators: false) {
                            HStack(spacing: 8) {
                                ForEach(Array(photoData.enumerated()), id: \.offset) { _, d in
                                    if let img = UIImage(data: d) {
                                        Image(uiImage: img)
                                            .resizable()
                                            .scaledToFill()
                                            .frame(width: 80, height: 80)
                                            .clipShape(RoundedRectangle(cornerRadius: 8))
                                    }
                                }
                            }
                        }
                    }
                } header: {
                    Text(photoData.isEmpty ? "Fotos" : "Fotos (\(photoData.count))")
                }

                if let errorMessage {
                    Section { Text(errorMessage).font(.footnote).foregroundStyle(.red) }
                }
            }
            .navigationTitle("Neuer Eintrag")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Abbrechen") { dismiss() }
                        .disabled(saveState != .idle)
                }
                ToolbarItem(placement: .confirmationAction) {
                    saveToolbarItem
                }
            }
            .onChange(of: photoSelection) { _, items in
                Task { await loadPhotos(from: items) }
            }
            .task { location.request() }
            .onChange(of: location.coordinate?.latitude) { _, _ in
                guard let coord = location.coordinate, locationName.isEmpty else { return }
                Task { await reverseGeocode(coord) }
            }
            .interactiveDismissDisabled(saveState != .idle)
        }
    }

    private func reverseGeocode(_ coord: CLLocationCoordinate2D) async {
        isReverseGeocoding = true
        defer { isReverseGeocoding = false }
        let geocoder = CLGeocoder()
        let loc = CLLocation(latitude: coord.latitude, longitude: coord.longitude)
        do {
            let placemarks = try await geocoder.reverseGeocodeLocation(loc, preferredLocale: Locale(identifier: "de_DE"))
            guard let p = placemarks.first else { return }
            // Sample: "Café Kaiser, Berlin" — name first, then locality fallback
            if let name = p.name, !name.isEmpty {
                locationName = name
                return
            }
            var parts: [String] = []
            if let street = p.thoroughfare { parts.append(street) }
            if let city = p.locality { parts.append(city) }
            if !parts.isEmpty { locationName = parts.joined(separator: ", ") }
        } catch {
            print("Reverse geocode failed: \(error)")
        }
    }

    @ViewBuilder
    private var saveToolbarItem: some View {
        switch saveState {
        case .idle:
            Button("Sichern") { Task { await save() } }
                .disabled(titel.trimmingCharacters(in: .whitespaces).isEmpty &&
                          text.trimmingCharacters(in: .whitespaces).isEmpty)
        case .savingEntry:
            ProgressView()
        case .uploadingMedia(let done, let total):
            Text("\(done)/\(total)").font(.caption.monospacedDigit())
        }
    }

    private func loadPhotos(from items: [PhotosPickerItem]) async {
        var loaded: [Data] = []
        for item in items {
            if let d = try? await item.loadTransferable(type: Data.self) {
                loaded.append(d)
            }
        }
        photoData = loaded
    }

    private func save() async {
        errorMessage = nil
        saveState = .savingEntry

        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        let tags = tagsInput
            .split(separator: ",")
            .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
            .filter { !$0.isEmpty }

        let coord = attachLocation ? location.coordinate : nil
        let body = DiaryCreateBody(
            datum: formatter.string(from: date),
            typ: isMilestone ? "meilenstein" : "eintrag",
            titel: titel.trimmingCharacters(in: .whitespaces).isEmpty ? nil : titel.trimmingCharacters(in: .whitespaces),
            text: text.trimmingCharacters(in: .whitespaces).isEmpty ? nil : text.trimmingCharacters(in: .whitespacesAndNewlines),
            tags: tags.isEmpty ? nil : tags,
            gpsLat: coord?.latitude,
            gpsLon: coord?.longitude,
            locationName: locationName.trimmingCharacters(in: .whitespaces).isEmpty ? nil : locationName,
            isMilestone: isMilestone
        )

        let entry: DiaryEntry
        do {
            entry = try await APIClient.shared.post("/api/dogs/\(dogId)/diary", body: body)
        } catch {
            errorMessage = error.localizedDescription
            saveState = .idle
            return
        }

        if !photoData.isEmpty {
            for (i, raw) in photoData.enumerated() {
                saveState = .uploadingMedia(done: i, total: photoData.count)
                let resized = ImageResize.resizedJPEG(from: raw)
                do {
                    _ = try await APIClient.shared.uploadFile(
                        "/api/dogs/\(dogId)/diary/\(entry.id)/media",
                        filename: "media_\(i + 1).jpg",
                        data: resized
                    )
                } catch {
                    errorMessage = "Eintrag gespeichert, Foto \(i + 1) fehlgeschlagen: \(error.localizedDescription)"
                    await onSaved()
                    saveState = .idle
                    return
                }
            }
        }

        await onSaved()
        dismiss()
    }
}
