import SwiftUI
import UIKit

/// Detail/edit screen for a single receipt, pushed from `ReceiptsListView`.
/// Edits a local `draft` copy; "Speichern" pushes it via
/// `ReceiptsAPI.sync([draft])`, "Löschen" confirms then calls
/// `ReceiptsAPI.delete(id:)` and pops back on success.
///
/// The body is deliberately split into small `@ViewBuilder` sections rather
/// than one large `Form { ... }` — a single body this size (many Sections,
/// Pickers, and conditionals) can make the Swift type-checker choke, and
/// there is no compiler available in this environment to catch that.
struct ReceiptDetailView: View {
    @State private var draft: Receipt

    @Environment(\.dismiss) private var dismiss

    @State private var isSaving = false
    @State private var didSave = false
    @State private var saveErrorMessage: String?

    @State private var isDeleting = false
    @State private var showDeleteConfirmation = false
    @State private var deleteErrorMessage: String?

    init(receipt: Receipt) {
        _draft = State(initialValue: receipt)
    }

    var body: some View {
        Form {
            imageSection
            merchantSection
            receiptSection
            amountSection
            categorySection
            paymentMethodSection
            lineItemsSection
            notesSection
            infoSection
            actionsSection
        }
        .zenithListBackground()
        .navigationTitle(draft.merchant.name.isEmpty ? "Beleg" : draft.merchant.name)
        .navigationBarTitleDisplayMode(.inline)
        .task {
            await loadPreviewIfNeeded()
        }
        .alert(
            "Beleg löschen?",
            isPresented: $showDeleteConfirmation
        ) {
            Button("Abbrechen", role: .cancel) {}
            Button("Löschen", role: .destructive) {
                Task { await performDelete() }
            }
        } message: {
            Text("Diese Aktion kann nicht rückgängig gemacht werden.")
        }
        .alert(
            "Löschen fehlgeschlagen",
            isPresented: Binding(
                get: { deleteErrorMessage != nil },
                set: { isPresented in
                    if !isPresented { deleteErrorMessage = nil }
                }
            )
        ) {
            Button("OK", role: .cancel) { deleteErrorMessage = nil }
        } message: {
            Text(deleteErrorMessage ?? "")
        }
    }

    // MARK: - Sections

    @ViewBuilder
    private var imageSection: some View {
        if let uiImage = dataURLImage {
            Section {
                Image(uiImage: uiImage)
                    .resizable()
                    .scaledToFit()
                    .frame(maxHeight: 260)
                    .frame(maxWidth: .infinity)
                    .overlay(Rectangle().strokeBorder(Color.zenithBorder, lineWidth: 1))
            }
            .listRowBackground(Color.zenithSurface)
            .listRowSeparatorTint(Color.zenithBorder)
        } else if let remoteURL = remoteImageURL {
            Section {
                remoteImageView(url: remoteURL)
            }
            .listRowBackground(Color.zenithSurface)
            .listRowSeparatorTint(Color.zenithBorder)
        }
    }

    private func remoteImageView(url: URL) -> some View {
        AsyncImage(url: url) { phase in
            switch phase {
            case .success(let image):
                image
                    .resizable()
                    .scaledToFit()
                    .frame(maxHeight: 260)
                    .frame(maxWidth: .infinity)
                    .overlay(Rectangle().strokeBorder(Color.zenithBorder, lineWidth: 1))
            case .empty:
                ProgressView()
                    .frame(maxWidth: .infinity, minHeight: 120)
            case .failure:
                EmptyView()
            @unknown default:
                EmptyView()
            }
        }
    }

    private var merchantSection: some View {
        Section {
            ZenithTextField(label: "Name", text: $draft.merchant.name)
            ZenithTextField(label: "Adresse", text: addressBinding)
            ZenithTextField(label: "Steuer-ID", text: taxIdBinding)
        } header: {
            Text("Händler").zenithLabelCapsStyle()
        }
        .listRowBackground(Color.zenithSurface)
        .listRowSeparatorTint(Color.zenithBorder)
    }

    private var receiptSection: some View {
        Section {
            DatePicker("Datum", selection: dateBinding, displayedComponents: .date)
                .zenithBodyStyle()
            ZenithTextField(label: "Belegnummer", text: receiptNumberBinding)
            Picker("Belegart", selection: $draft.documentType) {
                ForEach(Receipt.DocumentType.allCases, id: \.self) { type in
                    Text(type.displayLabel).tag(type)
                }
            }
            .zenithBodyStyle()
        } header: {
            Text("Beleg").zenithLabelCapsStyle()
        }
        .listRowBackground(Color.zenithSurface)
        .listRowSeparatorTint(Color.zenithBorder)
    }

    private var amountSection: some View {
        Section {
            ZenithAmountField(label: "Gesamtbetrag", value: totalAmountBinding)
            ZenithAmountField(label: "Netto", value: $draft.netAmount)
            ZenithAmountField(label: "Trinkgeld", value: $draft.tipAmount)
            ZenithTextField(label: "Währung", text: $draft.currency, autocorrectionDisabled: true)
            HStack {
                Text("Gesamt inkl. Trinkgeld").zenithBodyStyle()
                Spacer()
                Text(draft.grossWithTip.formatted(.currency(code: currencyCodeOrFallback)))
                    .zenithLabelMdStyle()
            }
        } header: {
            Text("Betrag").zenithLabelCapsStyle()
        }
        .listRowBackground(Color.zenithSurface)
        .listRowSeparatorTint(Color.zenithBorder)
    }

    private var categorySection: some View {
        Section {
            Picker("Kategorie", selection: $draft.suggestedCategory) {
                ForEach(Receipt.ReceiptCategory.allCases, id: \.self) { category in
                    Text(category.rawValue).tag(category)
                }
            }
            .zenithBodyStyle()
        } header: {
            Text("Kategorie").zenithLabelCapsStyle()
        }
        .listRowBackground(Color.zenithSurface)
        .listRowSeparatorTint(Color.zenithBorder)
    }

    private var paymentMethodSection: some View {
        Section {
            Picker("Zahlungsart", selection: $draft.paymentMethod) {
                Text("Keine Angabe").tag(Receipt.PaymentMethod?.none)
                ForEach(Receipt.PaymentMethod.allCases, id: \.self) { method in
                    Text(method.displayLabel).tag(Receipt.PaymentMethod?.some(method))
                }
            }
            .zenithBodyStyle()
        } header: {
            Text("Zahlungsart").zenithLabelCapsStyle()
        }
        .listRowBackground(Color.zenithSurface)
        .listRowSeparatorTint(Color.zenithBorder)
    }

    private var lineItemsSection: some View {
        Section {
            ForEach($draft.lineItems) { $item in
                lineItemRow(item: $item)
            }
            .onDelete { offsets in
                draft.lineItems.remove(atOffsets: offsets)
            }

            Button {
                draft.lineItems.append(Receipt.LineItem(description: "", quantity: 1, price: 0))
            } label: {
                Label("Position hinzufügen", systemImage: "plus")
            }
            .buttonStyle(.zenithPlain)
        } header: {
            Text("Positionen").zenithLabelCapsStyle()
        }
        .listRowBackground(Color.zenithSurface)
        .listRowSeparatorTint(Color.zenithBorder)
    }

    private func lineItemRow(item: Binding<Receipt.LineItem>) -> some View {
        VStack(alignment: .leading, spacing: ZenithSpacing.xs) {
            ZenithTextField(label: "Beschreibung", text: item.description)
            HStack(spacing: ZenithSpacing.xs) {
                TextField("Menge", value: item.quantity, format: .number)
                    .keyboardType(.decimalPad)
                    .frame(maxWidth: 70)
                    .zenithLabelMdStyle()
                Text("×")
                    .zenithBodySmStyle()
                TextField("Preis", value: item.price, format: .number)
                    .keyboardType(.decimalPad)
                    .zenithLabelMdStyle()
            }
        }
        .padding(.vertical, ZenithSpacing.unit)
    }

    private var notesSection: some View {
        Section {
            ZenithTextField(label: "Anlass", text: occasionBinding)
            ZenithTextField(label: "Teilnehmer", text: participantsBinding)
        } header: {
            Text("Notizen (Bewirtung)").zenithLabelCapsStyle()
        }
        .listRowBackground(Color.zenithSurface)
        .listRowSeparatorTint(Color.zenithBorder)
    }

    @ViewBuilder
    private var infoSection: some View {
        Section {
            if let created = ISO8601.parse(draft.createdAt) {
                HStack {
                    Text("Erstellt").zenithBodyStyle()
                    Spacer()
                    Text(Self.dateTimeFormatter.string(from: created)).zenithLabelMdStyle()
                }
            }
            if let updated = ISO8601.parse(draft.updatedAt) {
                HStack {
                    Text("Aktualisiert").zenithBodyStyle()
                    Spacer()
                    Text(Self.dateTimeFormatter.string(from: updated)).zenithLabelMdStyle()
                }
            }
            if draft.validation.needsUserReview {
                Label(draft.validation.reviewReason ?? "Bitte prüfen.", systemImage: "exclamationmark.triangle.fill")
                    .font(.zenithBodySm)
                    .foregroundStyle(Color.zenithPendingText)
                    .padding(ZenithSpacing.xs)
                    .background(Color.zenithPendingBg)
                    .overlay(Rectangle().strokeBorder(Color.zenithPendingBorder, lineWidth: 1))
            }
        } header: {
            Text("Info").zenithLabelCapsStyle()
        }
        .listRowBackground(Color.zenithSurface)
        .listRowSeparatorTint(Color.zenithBorder)
    }

    @ViewBuilder
    private var actionsSection: some View {
        Section {
            Button {
                Task { await save() }
            } label: {
                if isSaving {
                    ProgressView().tint(.white)
                } else {
                    Text("Speichern")
                }
            }
            .buttonStyle(.zenithPrimary)
            .disabled(isSaving)

            if didSave && saveErrorMessage == nil {
                HStack {
                    Spacer()
                    Label("Gespeichert.", systemImage: "checkmark.circle")
                        .foregroundStyle(Color.zenithScannedText)
                    Spacer()
                }
            }

            if let saveErrorMessage {
                Text(saveErrorMessage)
                    .zenithBodySmStyle(color: .zenithError)
            }

            Button {
                showDeleteConfirmation = true
            } label: {
                if isDeleting {
                    ProgressView()
                } else {
                    Text("Löschen")
                }
            }
            .buttonStyle(.zenithSecondaryDestructive)
            .disabled(isDeleting)
        }
        .listRowBackground(Color.zenithSurface)
        .listRowSeparatorTint(Color.zenithBorder)
    }

    // MARK: - Image

    /// `previewUrl` may be a `data:` URL (from `includePreview=1`) or an
    /// http(s) URL. This handles the `data:` case; `remoteImageURL` handles
    /// the other.
    private var dataURLImage: UIImage? {
        guard let previewUrl = draft.previewUrl, previewUrl.hasPrefix("data:") else { return nil }
        guard let commaIndex = previewUrl.firstIndex(of: ",") else { return nil }
        let base64 = String(previewUrl[previewUrl.index(after: commaIndex)...])
        guard let data = Data(base64Encoded: base64) else { return nil }
        return UIImage(data: data)
    }

    private var remoteImageURL: URL? {
        guard let previewUrl = draft.previewUrl,
              previewUrl.hasPrefix("http://") || previewUrl.hasPrefix("https://") else { return nil }
        return URL(string: previewUrl)
    }

    /// `ReceiptsAPI.list()` (used by the list screen) is called without
    /// `includePreview`, so `previewUrl` is typically nil at this point.
    /// Fetch the single receipt with its preview inlined rather than showing
    /// a blank image area. Only touches `previewUrl`, so it can't clobber
    /// any in-progress edit elsewhere on the draft.
    private func loadPreviewIfNeeded() async {
        guard draft.previewUrl == nil else { return }
        if let full = try? await ReceiptsAPI.get(id: draft.id) {
            draft.previewUrl = full.previewUrl
        }
    }

    // MARK: - Bindings for optional / nested fields

    private var addressBinding: Binding<String> {
        Binding(
            get: { draft.merchant.address ?? "" },
            set: { draft.merchant.address = $0.isEmpty ? nil : $0 }
        )
    }

    private var taxIdBinding: Binding<String> {
        Binding(
            get: { draft.merchant.taxId ?? "" },
            set: { draft.merchant.taxId = $0.isEmpty ? nil : $0 }
        )
    }

    private var receiptNumberBinding: Binding<String> {
        Binding(
            get: { draft.receiptNumber ?? "" },
            set: { draft.receiptNumber = $0.isEmpty ? nil : $0 }
        )
    }

    /// `draft.totalAmount.value` is a required `Double`, but `ZenithAmountField`
    /// takes `Binding<Double?>` — this small proxy adapts it. Mirrors the same
    /// pattern in `ReceiptReviewView.totalAmountBinding`: a momentarily empty
    /// field (while retyping) is ignored rather than zeroing out the total.
    private var totalAmountBinding: Binding<Double?> {
        Binding<Double?>(
            get: { draft.totalAmount.value },
            set: { newValue in
                if let newValue { draft.totalAmount.value = newValue }
            }
        )
    }

    private var occasionBinding: Binding<String> {
        Binding(
            get: { draft.hospitality?.occasion ?? "" },
            set: { newValue in
                if draft.hospitality == nil {
                    draft.hospitality = Receipt.Hospitality(occasion: nil, participants: nil)
                }
                draft.hospitality?.occasion = newValue.isEmpty ? nil : newValue
            }
        )
    }

    private var participantsBinding: Binding<String> {
        Binding(
            get: { draft.hospitality?.participants ?? "" },
            set: { newValue in
                if draft.hospitality == nil {
                    draft.hospitality = Receipt.Hospitality(occasion: nil, participants: nil)
                }
                draft.hospitality?.participants = newValue.isEmpty ? nil : newValue
            }
        )
    }

    /// `draft.date.isoDate` is a plain "YYYY-MM-DD" string (no time/zone
    /// component) — converted through a UTC-anchored formatter on both sides
    /// so round-tripping through `DatePicker` can't shift the calendar day.
    private var dateBinding: Binding<Date> {
        Binding(
            get: { Self.isoDateOnlyFormatter.date(from: draft.date.isoDate) ?? Date() },
            set: { draft.date.isoDate = Self.isoDateOnlyFormatter.string(from: $0) }
        )
    }

    private var currencyCodeOrFallback: String {
        draft.currency.isEmpty ? "EUR" : draft.currency
    }

    // MARK: - Actions

    private func save() async {
        isSaving = true
        saveErrorMessage = nil
        didSave = false
        defer { isSaving = false }
        do {
            try await ReceiptsAPI.sync([draft])
            didSave = true
        } catch {
            saveErrorMessage = error.localizedDescription
        }
    }

    private func performDelete() async {
        isDeleting = true
        deleteErrorMessage = nil
        defer { isDeleting = false }
        do {
            try await ReceiptsAPI.delete(id: draft.id)
            dismiss()
        } catch {
            deleteErrorMessage = error.localizedDescription
        }
    }

    // MARK: - Formatting helpers

    private static let isoDateOnlyFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(identifier: "UTC")
        return formatter
    }()

    private static let dateTimeFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateStyle = .medium
        formatter.timeStyle = .short
        formatter.locale = Locale(identifier: "de_DE")
        return formatter
    }()
}

// MARK: - German display labels

private extension Receipt.DocumentType {
    var displayLabel: String {
        switch self {
        case .kassenbon: return "Kassenbon"
        case .rechnung: return "Rechnung"
        case .tankbeleg: return "Tankbeleg"
        case .bewirtungsbeleg: return "Bewirtungsbeleg"
        case .parkticket: return "Parkticket"
        case .sonstiges: return "Sonstiges"
        }
    }
}

private extension Receipt.PaymentMethod {
    var displayLabel: String {
        switch self {
        case .bar: return "Bar"
        case .ecKarte: return "EC-Karte"
        case .kreditkarte: return "Kreditkarte"
        case .ueberweisung: return "Überweisung"
        case .paypal: return "PayPal"
        case .applePay: return "Apple Pay"
        case .googlePay: return "Google Pay"
        case .sonstige: return "Sonstige"
        }
    }
}
