import SwiftUI
import UIKit

/// The mandatory end-of-ride parking photo.
///
/// Not skippable: the architecture requires it and booking-service rejects an end
/// without a `photoUrl` (400). It is the only evidence trail for bad parking, which is
/// the main ops problem in a dockless fleet.
struct ParkingPhotoView: View {
    let captured: Data?
    let uploading: Bool
    let zoneRefused: Bool
    var parkingGuidance: ParkingGuidance?
    let onCaptured: (Data) -> Void
    let onRetake: () -> Void
    let onConfirm: () -> Void
    let onCancel: () -> Void

    @State private var showCamera = false

    /// An operator can leave both rider names blank, so fall back to a generic label rather than
    /// rendering an empty string at the rider.
    private func refusalBody(_ nearest: ParkingSpot?) -> String {
        guard let nearest else { return "blocked_zone_body".localized }
        let name = nearest.displayName ?? "parking_unnamed".localized
        // A rider redirected to a spot that charges should learn the price now, not when the
        // fare lands.
        if nearest.free {
            return String(format: "blocked_parking_body".localized, name, nearest.distanceMeters)
        }
        return String(
            format: "blocked_parking_body_paid".localized,
            name, nearest.distanceMeters, formatParkingFee(nearest.parkingFee)
        )
    }

    private var cameraAvailable: Bool {
        UIImagePickerController.isSourceTypeAvailable(.camera)
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 14) {
            Text("photo_title".localized).font(.beebSection)
            Text("photo_body".localized)
                .font(.beebBody)
                .foregroundStyle(Color.muted)

            // The ride is still running here  a zone refusal must not cost the photo.
            if zoneRefused {
                let nearest = parkingGuidance.flatMap { $0.parkingRequired ? $0.nearest : nil }
                HStack(spacing: 12) {
                    IconChip(glyph: "!", tone: .warning)
                    VStack(alignment: .leading, spacing: 2) {
                        Text((nearest == nil ? "blocked_zone_title" : "blocked_parking_title").localized)
                            .font(.beebBody)
                            .foregroundStyle(Color.warning)
                        // Naming the spot and the walk turns "you may not stop here" into an
                        // instruction. Without a confirmed nearest spot we say nothing more than
                        // before rather than guess.
                        Text(refusalBody(nearest))
                            .font(.beebCaption)
                            .foregroundStyle(Color.muted)
                    }
                }
                .padding(16)
                .beebCard()
            }

            viewfinder

            Spacer()

            if uploading {
                HStack(spacing: 12) {
                    ProgressView().tint(Color.brand)
                    Text("photo_uploading".localized)
                        .font(.beebBody)
                        .foregroundStyle(Color.muted)
                }
                .frame(maxWidth: .infinity)
            } else if captured != nil {
                BrandButton(title: "photo_confirm".localized, action: onConfirm)
                SecondaryButton(title: "photo_retake".localized, action: onRetake)
            } else {
                BrandButton(title: "photo_take".localized, enabled: cameraAvailable) {
                    showCamera = true
                }
                if !cameraAvailable {
                    Text("photo_permission_body".localized)
                        .font(.beebCaption)
                        .foregroundStyle(Color.muted)
                }
                SecondaryButton(title: "cancel".localized, action: onCancel)
            }
        }
        .padding(20)
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
        .background(Color.appBackground)
        .fullScreenCover(isPresented: $showCamera) {
            CameraPicker { data in
                showCamera = false
                if let data { onCaptured(data) }
            }
            .ignoresSafeArea()
        }
    }

    private var viewfinder: some View {
        ZStack {
            RoundedRectangle(cornerRadius: BeebRadius.card).fill(Color.canvas)

            if let captured, let image = UIImage(data: captured) {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFill()
                    .clipShape(RoundedRectangle(cornerRadius: BeebRadius.card))
                    .overlay(alignment: .topLeading) {
                        StatusBadge(text: "photo_captured".localized, tone: .success)
                            .padding(12)
                    }
            } else {
                VStack(spacing: 6) {
                    IconChip(glyph: "⛶", tone: .brand, size: 56)
                        .padding(.bottom, 8)
                    Text("photo_hint_full".localized)
                    Text("photo_hint_clear".localized)
                    Text("photo_hint_parked".localized)
                }
                .font(.beebCaption)
                .foregroundStyle(Color.muted)
                .multilineTextAlignment(.center)
            }
        }
        .aspectRatio(3.0 / 4.0, contentMode: .fit)
        .clipped()
    }
}

/// System camera, bridged into SwiftUI. SwiftUI has no native capture view  PhotosPicker
/// only reads the library, and this photo has to be taken now, at the scooter.
private struct CameraPicker: UIViewControllerRepresentable {
    let onResult: (Data?) -> Void

    func makeUIViewController(context: Context) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.sourceType = UIImagePickerController.isSourceTypeAvailable(.camera)
            ? .camera
            : .photoLibrary
        picker.delegate = context.coordinator
        return picker
    }

    func updateUIViewController(_ controller: UIImagePickerController, context: Context) {}

    func makeCoordinator() -> Coordinator { Coordinator(onResult: onResult) }

    final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        let onResult: (Data?) -> Void
        init(onResult: @escaping (Data?) -> Void) { self.onResult = onResult }

        func imagePickerController(
            _ picker: UIImagePickerController,
            didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
        ) {
            let image = info[.originalImage] as? UIImage
            // Compressed on device: this is evidence, not a gallery shot, and it has to
            // upload over mobile data while the rider is standing at the scooter.
            onResult(image?.jpegData(compressionQuality: 0.7))
        }

        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            onResult(nil)
        }
    }
}
