import Foundation
import Capacitor
import AVFoundation
import UIKit
import Photos

@objc(QRCodeStudioPlugin)
public class QRCodeStudioPlugin: CAPPlugin {
    private let implementation = QRCodeStudio()
    private var scanner: QRCodeScanner?
    private var scannerViewController: UIViewController?
    private var currentCall: CAPPluginCall?
    
    // MARK: - Plugin Methods
    
    @objc func scan(_ call: CAPPluginCall) {
        self.currentCall = call
        
        // Get scan options
        let formats = call.getArray("formats", String.self) ?? ["QR_CODE"]
        let showFlipCameraButton = call.getBool("showFlipCameraButton") ?? true
        let showTorchButton = call.getBool("showTorchButton") ?? true
        let prompt = call.getString("prompt") ?? "Scan QR Code"
        
        DispatchQueue.main.async { [weak self] in
            self?.presentScanner(
                formats: formats,
                showFlipCameraButton: showFlipCameraButton,
                showTorchButton: showTorchButton,
                prompt: prompt
            )
        }
    }
    
    @objc func generate(_ call: CAPPluginCall) {
        guard let type = call.getString("type"),
              let data = call.getObject("data") else {
            call.reject("Missing required parameters")
            return
        }
        
        let options = call.getObject("options") ?? [:]
        
        do {
            let qrData = try implementation.generate(
                type: type,
                data: data,
                options: options
            )
            call.resolve(qrData)
        } catch {
            call.reject("Failed to generate QR code", error.localizedDescription)
        }
    }
    
    @objc func stopScan(_ call: CAPPluginCall) {
        DispatchQueue.main.async { [weak self] in
            self?.dismissScanner()
            call.resolve()
        }
    }
    
    @objc func pauseScan(_ call: CAPPluginCall) {
        scanner?.pauseScanning()
        call.resolve()
    }
    
    @objc func resumeScan(_ call: CAPPluginCall) {
        scanner?.resumeScanning()
        call.resolve()
    }
    
    @objc func toggleTorch(_ call: CAPPluginCall) {
        do {
            try scanner?.toggleTorch()
            call.resolve()
        } catch {
            call.reject("Failed to toggle torch", error.localizedDescription)
        }
    }
    
    @objc func checkPermissions(_ call: CAPPluginCall) {
        let cameraStatus = AVCaptureDevice.authorizationStatus(for: .video)
        let photoStatus = PHPhotoLibrary.authorizationStatus()
        
        var permissions: [String: String] = [:]
        
        // Camera permission
        switch cameraStatus {
        case .authorized:
            permissions["camera"] = "granted"
        case .denied, .restricted:
            permissions["camera"] = "denied"
        case .notDetermined:
            permissions["camera"] = "prompt"
        @unknown default:
            permissions["camera"] = "prompt"
        }
        
        // Photo library permission
        switch photoStatus {
        case .authorized:
            permissions["photos"] = "granted"
        case .denied, .restricted:
            permissions["photos"] = "denied"
        case .notDetermined:
            permissions["photos"] = "prompt"
        case .limited:
            permissions["photos"] = "limited"
        @unknown default:
            permissions["photos"] = "prompt"
        }
        
        call.resolve(permissions)
    }
    
    @objc func requestPermissions(_ call: CAPPluginCall) {
        let permissions = call.getArray("permissions", String.self) ?? ["camera"]
        var results: [String: String] = [:]
        let group = DispatchGroup()
        
        if permissions.contains("camera") {
            group.enter()
            AVCaptureDevice.requestAccess(for: .video) { granted in
                results["camera"] = granted ? "granted" : "denied"
                group.leave()
            }
        }
        
        if permissions.contains("photos") {
            group.enter()
            PHPhotoLibrary.requestAuthorization { status in
                switch status {
                case .authorized:
                    results["photos"] = "granted"
                case .denied, .restricted:
                    results["photos"] = "denied"
                case .notDetermined:
                    results["photos"] = "prompt"
                case .limited:
                    results["photos"] = "limited"
                @unknown default:
                    results["photos"] = "prompt"
                }
                group.leave()
            }
        }
        
        group.notify(queue: .main) {
            call.resolve(results)
        }
    }
    
    @objc func scanFromFile(_ call: CAPPluginCall) {
        DispatchQueue.main.async { [weak self] in
            self?.presentImagePicker(call: call)
        }
    }
    
    @objc func saveToHistory(_ call: CAPPluginCall) {
        guard let item = call.getObject("item") else {
            call.reject("Missing history item")
            return
        }
        
        implementation.saveToHistory(item)
        call.resolve()
    }
    
    @objc func getHistory(_ call: CAPPluginCall) {
        let history = implementation.getHistory()
        call.resolve(["items": history])
    }
    
    @objc func clearHistory(_ call: CAPPluginCall) {
        implementation.clearHistory()
        call.resolve()
    }
    
    @objc func readBarcodesFromImage(_ call: CAPPluginCall) {
        guard let path = call.getString("path") else {
            call.reject("Missing image path")
            return
        }
        
        let formats = call.getArray("formats", String.self) ?? []
        
        // Load image from path
        if let image = loadImage(from: path) {
            scanner?.scanFromImageWithDetails(image, formats: formats) { [weak self] results, error in
                if let results = results {
                    call.resolve(["results": results])
                } else {
                    call.reject("Scan failed", error?.localizedDescription ?? "Unknown error")
                }
            }
        } else {
            call.reject("Failed to load image")
        }
    }
    
    @objc func getSupportedFormats(_ call: CAPPluginCall) {
        let formats = [
            "QR_CODE", "AZTEC", "CODE_128", "CODE_39", "CODE_93",
            "DATA_MATRIX", "EAN_13", "EAN_8", "ITF", "PDF_417",
            "UPC_A", "UPC_E"
        ]
        call.resolve(["formats": formats])
    }
    
    @objc func getTorchState(_ call: CAPPluginCall) {
        let isEnabled = scanner?.isTorchEnabled ?? false
        let isAvailable = scanner?.isTorchAvailable ?? false
        call.resolve([
            "isEnabled": isEnabled,
            "isAvailable": isAvailable
        ])
    }
    
    @objc func setZoom(_ call: CAPPluginCall) {
        guard let zoom = call.getFloat("zoom") else {
            call.reject("Missing zoom parameter")
            return
        }
        
        scanner?.setZoom(CGFloat(zoom))
        call.resolve()
    }
    
    @objc func generateBarcode(_ call: CAPPluginCall) {
        guard let format = call.getString("format"),
              let data = call.getString("data") else {
            call.reject("Missing required parameters")
            return
        }
        
        let width = call.getInt("width") ?? 300
        let height = call.getInt("height") ?? 100
        let displayText = call.getBool("displayText") ?? true
        let outputFormat = call.getString("outputFormat") ?? "png"
        
        do {
            let result = try implementation.generateBarcode(
                format: format,
                data: data,
                width: width,
                height: height,
                displayText: displayText,
                outputFormat: outputFormat
            )
            call.resolve(result)
        } catch {
            call.reject("Failed to generate barcode", error.localizedDescription)
        }
    }
    
    // MARK: - Private Methods
    
    private func loadImage(from path: String) -> UIImage? {
        if path.hasPrefix("file://") {
            let url = URL(string: path)
            if let data = try? Data(contentsOf: url!) {
                return UIImage(data: data)
            }
        } else if path.hasPrefix("data:image") {
            // Handle base64 data URL
            if let range = path.range(of: ";base64,") {
                let base64String = String(path[range.upperBound...])
                if let data = Data(base64Encoded: base64String) {
                    return UIImage(data: data)
                }
            }
        } else {
            // Try as file path
            return UIImage(contentsOfFile: path)
        }
        return nil
    }
    
    private func presentScanner(
        formats: [String],
        showFlipCameraButton: Bool,
        showTorchButton: Bool,
        prompt: String
    ) {
        let scannerVC = QRScannerViewController()
        scannerVC.formats = formats
        scannerVC.showFlipCameraButton = showFlipCameraButton
        scannerVC.showTorchButton = showTorchButton
        scannerVC.prompt = prompt
        scannerVC.delegate = self
        
        scanner = scannerVC.scanner
        scannerViewController = scannerVC
        
        let navController = UINavigationController(rootViewController: scannerVC)
        navController.modalPresentationStyle = .fullScreen
        
        bridge?.viewController?.present(navController, animated: true)
    }
    
    private func dismissScanner() {
        scannerViewController?.dismiss(animated: true) { [weak self] in
            self?.scanner = nil
            self?.scannerViewController = nil
        }
    }
    
    private func presentImagePicker(call: CAPPluginCall) {
        self.currentCall = call
        
        let picker = UIImagePickerController()
        picker.delegate = self
        picker.sourceType = .photoLibrary
        picker.allowsEditing = false
        
        bridge?.viewController?.present(picker, animated: true)
    }
}

// MARK: - QRScannerViewControllerDelegate

extension QRCodeStudioPlugin: QRScannerViewControllerDelegate {
    func scannerDidScan(result: String) {
        dismissScanner()
        
        // Parse the result
        let scanResult = implementation.parseScanResult(result)
        currentCall?.resolve(scanResult)
        currentCall = nil
    }
    
    func scannerDidCancel() {
        dismissScanner()
        currentCall?.reject("CANCELLED", "User cancelled scanning")
        currentCall = nil
    }
}

// MARK: - UIImagePickerControllerDelegate

extension QRCodeStudioPlugin: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    public func imagePickerController(
        _ picker: UIImagePickerController,
        didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]
    ) {
        picker.dismiss(animated: true)
        
        guard let image = info[.originalImage] as? UIImage else {
            currentCall?.reject("No image selected")
            currentCall = nil
            return
        }
        
        scanner?.scanFromImage(image) { [weak self] result, error in
            if let result = result {
                let scanResult = self?.implementation.parseScanResult(result) ?? [:]
                self?.currentCall?.resolve(scanResult)
            } else {
                self?.currentCall?.reject("Scan failed", error?.localizedDescription ?? "Unknown error")
            }
            self?.currentCall = nil
        }
    }
    
    public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true)
        currentCall?.reject("CANCELLED", "User cancelled image selection")
        currentCall = nil
    }
}

// MARK: - Scanner View Controller

protocol QRScannerViewControllerDelegate: AnyObject {
    func scannerDidScan(result: String)
    func scannerDidCancel()
}

class QRScannerViewController: UIViewController {
    let scanner = QRCodeScanner()
    weak var delegate: QRScannerViewControllerDelegate?
    
    var formats: [String] = ["QR_CODE"]
    var showFlipCameraButton: Bool = true
    var showTorchButton: Bool = true
    var prompt: String = "Scan QR Code"
    
    private var overlayView: UIView!
    private var promptLabel: UILabel!
    private var torchButton: UIButton!
    private var flipCameraButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        startScanning()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        scanner.stopScanning()
    }
    
    private func setupUI() {
        view.backgroundColor = .black
        
        // Navigation bar
        navigationItem.title = "QR Scanner"
        navigationItem.leftBarButtonItem = UIBarButtonItem(
            barButtonSystemItem: .cancel,
            target: self,
            action: #selector(cancelTapped)
        )
        
        // Overlay view
        overlayView = UIView()
        overlayView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        overlayView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(overlayView)
        
        // Prompt label
        promptLabel = UILabel()
        promptLabel.text = prompt
        promptLabel.textColor = .white
        promptLabel.textAlignment = .center
        promptLabel.font = .systemFont(ofSize: 16)
        promptLabel.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(promptLabel)
        
        // Torch button
        if showTorchButton {
            torchButton = UIButton(type: .system)
            torchButton.setImage(UIImage(systemName: "flashlight.off.fill"), for: .normal)
            torchButton.tintColor = .white
            torchButton.addTarget(self, action: #selector(torchTapped), for: .touchUpInside)
            torchButton.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(torchButton)
        }
        
        // Flip camera button
        if showFlipCameraButton {
            flipCameraButton = UIButton(type: .system)
            flipCameraButton.setImage(UIImage(systemName: "camera.rotate"), for: .normal)
            flipCameraButton.tintColor = .white
            flipCameraButton.addTarget(self, action: #selector(flipCameraTapped), for: .touchUpInside)
            flipCameraButton.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(flipCameraButton)
        }
        
        setupConstraints()
    }
    
    private func setupConstraints() {
        NSLayoutConstraint.activate([
            overlayView.topAnchor.constraint(equalTo: view.topAnchor),
            overlayView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            overlayView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            overlayView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            
            promptLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            promptLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 50)
        ])
        
        if let torchButton = torchButton {
            NSLayoutConstraint.activate([
                torchButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
                torchButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20),
                torchButton.widthAnchor.constraint(equalToConstant: 44),
                torchButton.heightAnchor.constraint(equalToConstant: 44)
            ])
        }
        
        if let flipCameraButton = flipCameraButton {
            NSLayoutConstraint.activate([
                flipCameraButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
                flipCameraButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20),
                flipCameraButton.widthAnchor.constraint(equalToConstant: 44),
                flipCameraButton.heightAnchor.constraint(equalToConstant: 44)
            ])
        }
    }
    
    private func startScanning() {
        scanner.startScanning(in: view, formats: formats) { [weak self] result, error in
            if let result = result {
                self?.delegate?.scannerDidScan(result: result)
            } else if let error = error {
                self?.showError(error.localizedDescription)
            }
        }
        
        // Create scan area
        let scanAreaSize = min(view.bounds.width, view.bounds.height) * 0.7
        let scanAreaRect = CGRect(
            x: (view.bounds.width - scanAreaSize) / 2,
            y: (view.bounds.height - scanAreaSize) / 2,
            width: scanAreaSize,
            height: scanAreaSize
        )
        
        scanner.configureScanArea(rect: scanAreaRect)
        createScanAreaOverlay(rect: scanAreaRect)
    }
    
    private func createScanAreaOverlay(rect: CGRect) {
        let path = UIBezierPath(rect: overlayView.bounds)
        let scanPath = UIBezierPath(roundedRect: rect, cornerRadius: 10)
        path.append(scanPath.reversing())
        
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = path.cgPath
        shapeLayer.fillColor = UIColor.black.withAlphaComponent(0.5).cgColor
        
        overlayView.layer.mask = shapeLayer
        
        // Add corner markers
        addCornerMarkers(to: rect)
    }
    
    private func addCornerMarkers(to rect: CGRect) {
        let markerLength: CGFloat = 30
        let markerWidth: CGFloat = 4
        let markerColor = UIColor.white
        
        // Top-left
        addCornerMarker(
            at: CGPoint(x: rect.minX, y: rect.minY),
            horizontal: true,
            vertical: true,
            length: markerLength,
            width: markerWidth,
            color: markerColor
        )
        
        // Top-right
        addCornerMarker(
            at: CGPoint(x: rect.maxX, y: rect.minY),
            horizontal: true,
            vertical: true,
            length: markerLength,
            width: markerWidth,
            color: markerColor,
            flipHorizontal: true
        )
        
        // Bottom-left
        addCornerMarker(
            at: CGPoint(x: rect.minX, y: rect.maxY),
            horizontal: true,
            vertical: true,
            length: markerLength,
            width: markerWidth,
            color: markerColor,
            flipVertical: true
        )
        
        // Bottom-right
        addCornerMarker(
            at: CGPoint(x: rect.maxX, y: rect.maxY),
            horizontal: true,
            vertical: true,
            length: markerLength,
            width: markerWidth,
            color: markerColor,
            flipHorizontal: true,
            flipVertical: true
        )
    }
    
    private func addCornerMarker(
        at point: CGPoint,
        horizontal: Bool,
        vertical: Bool,
        length: CGFloat,
        width: CGFloat,
        color: UIColor,
        flipHorizontal: Bool = false,
        flipVertical: Bool = false
    ) {
        if horizontal {
            let hView = UIView()
            hView.backgroundColor = color
            hView.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(hView)
            
            NSLayoutConstraint.activate([
                hView.widthAnchor.constraint(equalToConstant: length),
                hView.heightAnchor.constraint(equalToConstant: width),
                flipHorizontal ?
                    hView.trailingAnchor.constraint(equalTo: view.leadingAnchor, constant: point.x) :
                    hView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: point.x),
                hView.topAnchor.constraint(equalTo: view.topAnchor, constant: point.y - (flipVertical ? width : 0))
            ])
        }
        
        if vertical {
            let vView = UIView()
            vView.backgroundColor = color
            vView.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(vView)
            
            NSLayoutConstraint.activate([
                vView.widthAnchor.constraint(equalToConstant: width),
                vView.heightAnchor.constraint(equalToConstant: length),
                vView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: point.x - (flipHorizontal ? width : 0)),
                flipVertical ?
                    vView.bottomAnchor.constraint(equalTo: view.topAnchor, constant: point.y) :
                    vView.topAnchor.constraint(equalTo: view.topAnchor, constant: point.y)
            ])
        }
    }
    
    private func showError(_ message: String) {
        let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default) { [weak self] _ in
            self?.delegate?.scannerDidCancel()
        })
        present(alert, animated: true)
    }
    
    @objc private func cancelTapped() {
        delegate?.scannerDidCancel()
    }
    
    @objc private func torchTapped() {
        do {
            try scanner.toggleTorch()
            let isOn = torchButton.currentImage == UIImage(systemName: "flashlight.off.fill")
            torchButton.setImage(
                UIImage(systemName: isOn ? "flashlight.on.fill" : "flashlight.off.fill"),
                for: .normal
            )
        } catch {
            showError(error.localizedDescription)
        }
    }
    
    @objc private func flipCameraTapped() {
        do {
            try scanner.flipCamera()
        } catch {
            showError(error.localizedDescription)
        }
    }
}