import SwiftUI
import SwiftData
import PhotosUI

struct RouteDetailView: View {
    let routeId: Int
    let fallbackName: String

    @Environment(\.dismiss) private var dismiss
    @Environment(AuthSession.self) private var auth
    @Query private var allPhotoLocations: [PhotoLocation]

    @State private var detail: RouteDetail?
    @State private var isLoading = false
    @State private var errorMessage: String?
    @State private var tappedPhotoUrl: String?

    @State private var newPhotoSelection: [PhotosPickerItem] = []
    @State private var isUploadingPhoto = false
    @State private var photoUploadProgress: (done: Int, total: Int) = (0, 0)
    @State private var photoErrorMessage: String?

    @State private var showEditSheet = false
    @State private var showDeleteAlert = false
    @State private var isDeleting = false

    @State private var shareItems: [Any]?
    @State private var isGeneratingShareImage = false

    private var isOwn: Bool {
        guard let detail, let myId = auth.profile?.id else { return false }
        return detail.userId == myId
    }

    private var photoLocations: [PhotoLocation] {
        allPhotoLocations.filter { $0.routeId == routeId }
    }

    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 16) {
                if let detail {
                    MiniRouteMap(
                        track: detail.gpsTrack,
                        lineWidth: 4,
                        photoLocations: photoLocations,
                        onPhotoTap: { loc in tappedPhotoUrl = loc.photoUrl }
                    )
                    .frame(height: 320)
                    .clipShape(RoundedRectangle(cornerRadius: 16))
                    .padding(.horizontal)

                    HStack(spacing: 12) {
                        StatTile(value: formatKm(detail.distanzKm), label: "Distanz", icon: "ruler")
                        StatTile(value: formatMin(detail.dauerMin), label: "Dauer", icon: "clock")
                        StatTile(value: "\(detail.gpsTrack.count)", label: "Punkte", icon: "point.3.connected.trianglepath.dotted")
                    }
                    .padding(.horizontal)

                    if let beschreibung = detail.beschreibung, !beschreibung.isEmpty {
                        Text(beschreibung)
                            .font(.body)
                            .padding(.horizontal)
                    }

                    photosSection(for: detail)
                        .padding(.horizontal)

                    Spacer(minLength: 24)
                } else if isLoading {
                    ProgressView().padding(.top, 80)
                } else if let error = errorMessage {
                    ContentUnavailableView(
                        "Fehler",
                        systemImage: "exclamationmark.triangle",
                        description: Text(error)
                    )
                    .padding(.top, 60)
                }
            }
        }
        .navigationTitle(detail?.name ?? fallbackName)
        .navigationBarTitleDisplayMode(.inline)
        .task { await load() }
        .onChange(of: newPhotoSelection) { _, items in
            guard !items.isEmpty else { return }
            Task { await uploadSelected(items: items) }
        }
        .toolbar {
            if let detail {
                ToolbarItem(placement: .topBarTrailing) {
                    Menu {
                        Button { Task { await shareAsImage() } } label: {
                            Label("Als Bild teilen", systemImage: "photo")
                        }
                        .disabled(isGeneratingShareImage)
                        Button { shareAsGPX() } label: {
                            Label("Als GPX-Datei teilen", systemImage: "doc.text")
                        }
                        if isOwn {
                            Divider()
                            Button {
                                showEditSheet = true
                            } label: {
                                Label("Bearbeiten", systemImage: "pencil")
                            }
                            Button(role: .destructive) {
                                showDeleteAlert = true
                            } label: {
                                Label("Löschen", systemImage: "trash")
                            }
                        }
                    } label: {
                        if isGeneratingShareImage {
                            ProgressView()
                        } else {
                            Image(systemName: "ellipsis.circle")
                        }
                    }
                    .disabled(isDeleting)
                    .accessibilityIdentifier("routeDetailMenu_\(detail.id)")
                }
            }
        }
        .sheet(isPresented: $showEditSheet) {
            if let detail {
                EditRouteSheet(detail: detail) { updated in
                    self.detail = updated
                }
            }
        }
        .alert("Tour wirklich löschen?", isPresented: $showDeleteAlert) {
            Button("Abbrechen", role: .cancel) {}
            Button("Löschen", role: .destructive) { Task { await deleteRoute() } }
        } message: {
            Text("Die Tour wird unwiderruflich gelöscht — auch alle Fotos.")
        }
        .sheet(item: Binding(
            get: { tappedPhotoUrl.map(IdentifiedURL.init) },
            set: { tappedPhotoUrl = $0?.value }
        )) { item in
            PhotoViewerSheet(path: item.value)
        }
        .sheet(isPresented: Binding(
            get: { shareItems != nil },
            set: { if !$0 { shareItems = nil } }
        )) {
            if let items = shareItems {
                ShareSheet(items: items)
            }
        }
    }

    private func shareAsImage() async {
        guard let detail else { return }
        isGeneratingShareImage = true
        defer { isGeneratingShareImage = false }
        if let img = await RouteShareImage.render(detail: detail) {
            shareItems = [img]
        }
    }

    private func shareAsGPX() {
        guard let detail else { return }
        if let url = GPXExporter.write(detail: detail) {
            shareItems = [url]
        }
    }

    @ViewBuilder
    private func photosSection(for detail: RouteDetail) -> some View {
        let urls = detail.fotoUrls ?? []
        VStack(alignment: .leading, spacing: 8) {
            HStack {
                Text(urls.isEmpty ? "Fotos" : "Fotos (\(urls.count))")
                    .font(.headline)
                Spacer()
                PhotosPicker(
                    selection: $newPhotoSelection,
                    maxSelectionCount: 5,
                    matching: .images
                ) {
                    Label("Foto hinzufügen", systemImage: "photo.badge.plus")
                        .font(.subheadline)
                }
                .disabled(isUploadingPhoto)
            }

            if isUploadingPhoto {
                HStack(spacing: 8) {
                    ProgressView()
                    Text("Lade \(photoUploadProgress.done + 1)/\(photoUploadProgress.total)…")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
            }

            if let photoErrorMessage {
                Text(photoErrorMessage)
                    .font(.caption)
                    .foregroundStyle(.red)
            }

            if !urls.isEmpty {
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 10) {
                        ForEach(urls, id: \.self) { path in
                            photoThumb(path)
                        }
                    }
                }
            } else if !isUploadingPhoto {
                Text("Noch keine Fotos. Über den Button oben kannst du welche hinzufügen.")
                    .font(.footnote)
                    .foregroundStyle(.secondary)
            }
        }
    }

    private func photoThumb(_ path: String) -> some View {
        let url = URL(string: "https://banyaro.app\(path)")
        return AsyncImage(url: url) { phase in
            switch phase {
            case .success(let img):
                img.resizable().scaledToFill()
            default:
                Rectangle().fill(.gray.opacity(0.15))
            }
        }
        .frame(width: 160, height: 160)
        .clipShape(RoundedRectangle(cornerRadius: 10))
    }

    private func load() async {
        isLoading = true
        errorMessage = nil
        defer { isLoading = false }
        do {
            detail = try await APIClient.shared.get("/api/routes/\(routeId)")
        } catch {
            errorMessage = error.localizedDescription
        }
    }

    private func uploadSelected(items: [PhotosPickerItem]) async {
        isUploadingPhoto = true
        photoErrorMessage = nil
        photoUploadProgress = (0, items.count)
        defer {
            isUploadingPhoto = false
            newPhotoSelection = []
        }

        for (index, item) in items.enumerated() {
            photoUploadProgress = (index, items.count)
            guard let raw = try? await item.loadTransferable(type: Data.self) else { continue }
            let resized = ImageResize.resizedJPEG(from: raw)
            do {
                try await APIClient.shared.uploadFile(
                    "/api/routes/\(routeId)/photo",
                    filename: "photo_\(Int(Date.now.timeIntervalSince1970))_\(index + 1).jpg",
                    data: resized
                )
            } catch {
                photoErrorMessage = "Foto \(index + 1) konnte nicht hochgeladen werden: \(error.localizedDescription)"
                break
            }
        }
        // Refresh detail to pick up the new foto_urls.
        await load()
    }

    private func deleteRoute() async {
        isDeleting = true
        defer { isDeleting = false }
        do {
            try await APIClient.shared.delete("/api/routes/\(routeId)")
            dismiss()
        } catch {
            errorMessage = error.localizedDescription
        }
    }

    private func formatKm(_ km: Double?) -> String {
        guard let km else { return "—" }
        return String(format: "%.2f km", km)
    }

    private func formatMin(_ mins: Int?) -> String {
        guard let mins else { return "—" }
        if mins >= 60 { return "\(mins / 60) h \(mins % 60) min" }
        return "\(mins) min"
    }
}

/// Wrapper so we can use sheet(item:) with a plain String URL path.
private struct IdentifiedURL: Identifiable {
    let value: String
    var id: String { value }
}

private struct PhotoViewerSheet: View {
    let path: String
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        NavigationStack {
            ZStack {
                Color.black.ignoresSafeArea()
                if let url = URL(string: "https://banyaro.app\(path)") {
                    AsyncImage(url: url) { phase in
                        switch phase {
                        case .success(let img):
                            img.resizable().scaledToFit()
                        case .failure:
                            ContentUnavailableView("Foto nicht ladbar", systemImage: "photo.badge.exclamationmark")
                                .foregroundStyle(.white)
                        default:
                            ProgressView().tint(.white)
                        }
                    }
                }
            }
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button { dismiss() } label: { Image(systemName: "xmark") }
                        .tint(.white)
                }
            }
        }
    }
}

private struct StatTile: View {
    let value: String
    let label: String
    let icon: String

    var body: some View {
        VStack(spacing: 6) {
            Image(systemName: icon)
                .foregroundStyle(Color.accentColor)
            Text(value)
                .font(.headline)
            Text(label)
                .font(.caption)
                .foregroundStyle(.secondary)
        }
        .frame(maxWidth: .infinity)
        .padding(.vertical, 12)
        .background(.background.secondary, in: RoundedRectangle(cornerRadius: 12))
    }
}
