import SwiftUI
import Bedrock
import AVFoundation

struct QRScannerView: View {
    @Environment(\.dismiss) private var dismiss
    let onScan: (String) -> Void
    
    @State private var scannedCode: String?
    @State private var isScanning = true
    @State private var showingPermissionDenied = false
    
    var body: some View {
        NavigationStack {
            ZStack {
                if isScanning {
                    QRScannerRepresentable(scannedCode: $scannedCode)
                        .ignoresSafeArea()
                    
                    // Overlay with scanning frame
                    ScannerOverlayView()
                }
                
                if let scannedCode {
                    ScannedResultView(code: scannedCode) {
                        onScan(scannedCode)
                    }
                }
            }
            .navigationTitle(String.localized("Scan Card"))
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button(String.localized("Cancel")) {
                        dismiss()
                    }
                }
            }
            .onChange(of: scannedCode) { _, newValue in
                if newValue != nil {
                    isScanning = false
                }
            }
            .onAppear {
                checkCameraPermission()
            }
            .alert(String.localized("Camera Access Required"), isPresented: $showingPermissionDenied) {
                Button(String.localized("Open Settings")) {
                    if let url = URL(string: UIApplication.openSettingsURLString) {
                        UIApplication.shared.open(url)
                    }
                }
                Button(String.localized("Cancel"), role: .cancel) {
                    dismiss()
                }
            } message: {
                Text("Please allow camera access in Settings to scan QR codes.")
            }
        }
    }
    
    private func checkCameraPermission() {
        switch AVCaptureDevice.authorizationStatus(for: .video) {
        case .authorized:
            break
        case .notDetermined:
            AVCaptureDevice.requestAccess(for: .video) { granted in
                if !granted {
                    Task { @MainActor in
                        showingPermissionDenied = true
                    }
                }
            }
        case .denied, .restricted:
            showingPermissionDenied = true
        @unknown default:
            break
        }
    }
}

private struct ScannerOverlayView: View {
    var body: some View {
        GeometryReader { geometry in
            let size = min(geometry.size.width, geometry.size.height) * 0.7
            
            ZStack {
                // Dimmed background
                Color.black.opacity(Design.Opacity.medium)
                
                // Clear center
                RoundedRectangle(cornerRadius: Design.CornerRadius.large)
                    .frame(width: size, height: size)
                    .blendMode(.destinationOut)
            }
            .compositingGroup()
            
            // Scanning frame corners
            RoundedRectangle(cornerRadius: Design.CornerRadius.large)
                .stroke(Color.Accent.red, lineWidth: Design.LineWidth.thick)
                .frame(width: size, height: size)
                .position(x: geometry.size.width / 2, y: geometry.size.height / 2)
            
            // Instructions
            VStack {
                Spacer()
                
                Text("Point at a QR code")
                    .font(.headline)
                    .foregroundStyle(Color.Text.inverted)
                    .padding(Design.Spacing.medium)
                    .background(Color.black.opacity(Design.Opacity.medium))
                    .clipShape(.rect(cornerRadius: Design.CornerRadius.medium))
                    .padding(.bottom, Design.Spacing.xxxLarge)
            }
            .frame(maxWidth: .infinity)
        }
    }
}

private struct ScannedResultView: View {
    let code: String
    let onConfirm: () -> Void
    
    private var isVCard: Bool {
        code.contains("BEGIN:VCARD")
    }
    
    private var parsedName: String? {
        guard isVCard else { return nil }
        let lines = code.components(separatedBy: "\n")
        for line in lines {
            if line.hasPrefix("FN:") {
                return String(line.dropFirst(3))
            }
        }
        return nil
    }
    
    var body: some View {
        VStack(spacing: Design.Spacing.xLarge) {
            Image(systemName: isVCard ? "person.crop.circle.badge.checkmark" : "qrcode")
                .font(.system(size: Design.BaseFontSize.display * 2))
                .foregroundStyle(Color.Accent.red)
            
            if isVCard {
                VStack(spacing: Design.Spacing.small) {
                    Text("Card Found!")
                        .font(.title2)
                        .bold()
                        .foregroundStyle(Color.Text.primary)
                    
                    if let name = parsedName {
                        Text(name)
                            .font(.headline)
                            .foregroundStyle(Color.Text.secondary)
                    }
                }
            } else {
                Text("QR Code Scanned")
                    .font(.title2)
                    .bold()
                    .foregroundStyle(Color.Text.primary)
            }
            
            if isVCard {
                Button(String.localized("Save Contact"), systemImage: "person.badge.plus") {
                    onConfirm()
                }
                .buttonStyle(.borderedProminent)
                .tint(Color.Accent.red)
                .controlSize(.large)
            } else {
                Text("This doesn't appear to be a business card QR code.")
                    .font(.subheadline)
                    .foregroundStyle(Color.Text.secondary)
                    .multilineTextAlignment(.center)
                    .padding(.horizontal, Design.Spacing.xLarge)
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.AppBackground.base)
    }
}

// MARK: - Camera View Representable

private struct QRScannerRepresentable: UIViewControllerRepresentable {
    @Binding var scannedCode: String?
    
    func makeUIViewController(context: Context) -> QRScannerViewController {
        let controller = QRScannerViewController()
        controller.delegate = context.coordinator
        return controller
    }
    
    func updateUIViewController(_ uiViewController: QRScannerViewController, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator(scannedCode: $scannedCode)
    }
    
    class Coordinator: NSObject, QRScannerViewControllerDelegate {
        @Binding var scannedCode: String?
        
        init(scannedCode: Binding<String?>) {
            _scannedCode = scannedCode
        }
        
        func didScanCode(_ code: String) {
            Task { @MainActor in
                scannedCode = code
            }
        }
    }
}

// MARK: - Scanner View Controller

protocol QRScannerViewControllerDelegate: AnyObject {
    func didScanCode(_ code: String)
}

private class QRScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
    weak var delegate: QRScannerViewControllerDelegate?
    
    private var captureSession: AVCaptureSession?
    private var previewLayer: AVCaptureVideoPreviewLayer?
    private var hasScanned = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupCamera()
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        previewLayer?.frame = view.bounds
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        startScanning()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        stopScanning()
    }
    
    private func setupCamera() {
        let session = AVCaptureSession()
        
        guard let device = AVCaptureDevice.default(for: .video),
              let input = try? AVCaptureDeviceInput(device: device) else {
            return
        }
        
        if session.canAddInput(input) {
            session.addInput(input)
        }
        
        let output = AVCaptureMetadataOutput()
        if session.canAddOutput(output) {
            session.addOutput(output)
            output.setMetadataObjectsDelegate(self, queue: .main)
            output.metadataObjectTypes = [.qr]
        }
        
        let previewLayer = AVCaptureVideoPreviewLayer(session: session)
        previewLayer.videoGravity = .resizeAspectFill
        previewLayer.frame = view.bounds
        view.layer.addSublayer(previewLayer)
        
        self.captureSession = session
        self.previewLayer = previewLayer
    }
    
    private func startScanning() {
        guard let session = captureSession, !session.isRunning else { return }
        let capturedSession = session
        Task.detached {
            capturedSession.startRunning()
        }
    }
    
    private func stopScanning() {
        guard let session = captureSession, session.isRunning else { return }
        let capturedSession = session
        Task.detached {
            capturedSession.stopRunning()
        }
    }
    
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        guard !hasScanned,
              let metadataObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject,
              let code = metadataObject.stringValue else {
            return
        }
        
        hasScanned = true
        AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
        delegate?.didScanCode(code)
    }
}

#Preview {
    QRScannerView { code in
        Design.debugLog("Scanned: \(code)")
    }
}
