//
//  ARViewController.swift
//  PlaygroundBook
//
//  Created by 日々野清高 on 2025/04/15.
//

import ARKit
import UIKit
import PlaygroundSupport
import AudioToolbox

public class ARViewController: UIViewController, ARSCNViewDelegate, PlaygroundLiveViewSafeAreaContainer,PlaygroundLiveViewMessageHandler {
    var sceneView: ARSCNView!
    var tanzakuColor: UIColor = .systemPink
    var markerNode: SCNNode? //ARマーカー
    
    public override func viewDidLoad() {
        super.viewDidLoad()
        
        // ARSCNViewのセットアップ
        sceneView = ARSCNView(frame: view.bounds)
        sceneView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(sceneView)
        
        sceneView.delegate = self
        sceneView.autoenablesDefaultLighting = true
        
        // マーカー画像を読み込む
        guard let markerImage = UIImage(named: "marker.png")?.cgImage else {
            fatalError("marker.png を追加してください")
        }
        
        // マーカーを設定
        let referenceImage = ARReferenceImage(markerImage, orientation: .up, physicalWidth: 0.17)
        referenceImage.name = "tanzaku-marker"
        
        let config = ARWorldTrackingConfiguration()
        config.detectionImages = [referenceImage]
        config.planeDetection = .horizontal
        config.isLightEstimationEnabled = true
        
        sceneView.session.run(config)
        
        // 撮影ボタンを追加
        let captureButton = UIButton(type: .system)
        captureButton.setTitle("📸 撮影", for: .normal)
        captureButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
        captureButton.backgroundColor = UIColor.white.withAlphaComponent(0.8)
        captureButton.setTitleColor(.black, for: .normal)
        captureButton.layer.cornerRadius = 8
        captureButton.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(captureButton)

        // オートレイアウトで画面下中央に配置
        NSLayoutConstraint.activate([
            captureButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            captureButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20),
            captureButton.widthAnchor.constraint(equalToConstant: 120),
            captureButton.heightAnchor.constraint(equalToConstant: 44)
        ])

        captureButton.addTarget(self, action: #selector(captureScene), for: .touchUpInside)
    }
    @objc func captureScene() {
        let image = sceneView.snapshot()
        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
        
        // 効果音（シャッター音など）
        AudioServicesPlaySystemSound(1108)
        
        // 簡単なフィードバック（バイブ or フラッシュなど）
        let flashView = UIView(frame: view.bounds)
        flashView.backgroundColor = .white
        flashView.alpha = 0
        view.addSubview(flashView)
        
        UIView.animate(withDuration: 0.1, animations: {
            flashView.alpha = 1
        }) { _ in
            UIView.animate(withDuration: 0.1, animations: {
                flashView.alpha = 0
            }) { _ in
                flashView.removeFromSuperview()
            }
        }
    }
    // マーカー検出時の処理（初回のみ）
    public func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        guard anchor is ARImageAnchor else { return }
        
        AudioServicesPlaySystemSound(SystemSoundID(1016))
        self.markerNode = node //マーカーノードとする。
        markerNode?.transform = node.transform //調整を加えておく
        //初期ー基準の短冊の位置
        let defaultMessage = "旭高原七夕まつり"
        let x = 0.0
        let y = 0.5 //マーカーの50cm上に置く
        let z = 0.0
        let offset = SCNVector3(x, y, z)
        addTanzakuNode(message: defaultMessage, colorCode: 1, to: node, positionOffset: offset, imageName: "tanzakuKIKI")
    }
    
    // マーカーの位置更新に対応
    public func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        guard anchor is ARImageAnchor else { return }
        //AudioServicesPlaySystemSound(SystemSoundID(1015))
        // マーカー位置の更新を追従させる
        markerNode?.transform = node.transform
    }
    
    //playgroundからメッセージを受信する。
    public func receive(_ message: PlaygroundValue) {
        switch message {
        case .dictionary(let dict):
            if case let .string(messageText)? = dict["message"],
               case let .integer(colorCode)? = dict["colorCode"] {
                // offsetX/Y/Z を取得（なければ0）
                let x: Float
                if case let .floatingPoint(val)? = dict["offsetX"] {
                    x = Float(val)
                } else {
                    x = 0.0
                }

                let y: Float
                if case let .floatingPoint(val)? = dict["offsetY"] {
                    y = Float(val)
                } else {
                    y = 0.0
                }

                let z: Float
                if case let .floatingPoint(val)? = dict["offsetZ"] {
                    z = Float(val)
                } else {
                    z = 0.0
                }
                let offset = SCNVector3(x, y, z)
                if let node = self.markerNode {
                    self.addTanzakuNode(message: messageText, colorCode: colorCode, to: node, positionOffset: offset, imageName: "tanzakuKIKI")
                } else {
                    print("⚠️ マーカーがまだ見つかっていません")
                }
            }
        default:
            return
        }
    }

    
    func addTanzakuNode(message: String, colorCode: Int, to parentNode: SCNNode, positionOffset: SCNVector3, imageName: String)
    {
        let tanzaku = SCNPlane(width: 0.05, height: 0.15)
        tanzaku.firstMaterial?.diffuse.contents = colorFromCode(colorCode).withAlphaComponent(0.9)
        let tanzakuNode = SCNNode(geometry: tanzaku)
        tanzakuNode.eulerAngles = SCNVector3Zero
        
        // 画像を追加（短冊の最上部横中央）
        if let image = UIImage(named: imageName) {
            let imagePlane = SCNPlane(width: 0.03, height: 0.03)  // 画像のサイズ調整
            imagePlane.firstMaterial?.diffuse.contents = image

            let imageNode = SCNNode(geometry: imagePlane)
            
            // 短冊の最上部横中央に配置
            let tanzakuHeight: Float = 0.15 // 短冊の高さ

            imageNode.position = SCNVector3(
                x: 0.0,  // 横中央
                y: tanzakuHeight / 2,  // 最上部
                z: 0.001   // z軸の位置（適宜調整）
            )

            tanzakuNode.addChildNode(imageNode)
        }

        let verticalText = message
        let maxHeight: Float = 0.14
        let characterSpacing: Float = 0.01
        let columnSpacing: Float = 0.01
        let topMargin: Float = 0.015

        let maxRows = Int(floor((maxHeight - topMargin) / characterSpacing))
        let totalColumns = Int(ceil(Float(verticalText.count) / Float(maxRows)))

        let baseX: Float = 0.0
        let baseY: Float = 0.07
        let totalWidth = Float(totalColumns - 1) * columnSpacing
        let startX = baseX + totalWidth / 2

        var currentColumn = 0
        var currentRow = 0

        // 文字色の条件分岐
        let textColor: UIColor = (colorCode == 4 || colorCode == 9) ? .black : .white
        
        for char in verticalText {
            let text = SCNText(string: String(char), extrusionDepth: 0.2)
            text.font = UIFont.systemFont(ofSize: 2)
            text.firstMaterial?.diffuse.contents = textColor

            let textNode = SCNNode(geometry: text)
            textNode.scale = SCNVector3(0.002, 0.002, 0.002)

            let (minBound, maxBound) = text.boundingBox
            let textWidth = (maxBound.x - minBound.x) * 0.002

            let columnX = startX - Float(currentColumn) * columnSpacing
            let rowY = baseY - Float(currentRow) * characterSpacing - topMargin

            textNode.position = SCNVector3(columnX - textWidth / 2, rowY, 0.001)
            tanzakuNode.addChildNode(textNode)

            currentRow += 1
            if currentRow >= maxRows {
                currentColumn += 1
                currentRow = 0
            }
        }

        tanzakuNode.position = parentNode.position
        parentNode.addChildNode(tanzakuNode)
        // 現在位置から目標位置までアニメーション
        let moveAction = SCNAction.move(by: positionOffset, duration: TimeInterval(2.0))
        moveAction.timingMode = SCNActionTimingMode.easeInEaseOut
        // アニメーション実行
        tanzakuNode.runAction(moveAction)
        //回転アニメーション
        // ランダムな回転角度（±5〜60度くらい）
        let angle = Float.random(in: 5...60) * (.pi / 180)  // ラジアンに変換
        let durate = Double.random(in: 1.5...3.0)         // 動作の速さもランダム
        
        let rotateLeft = SCNAction.rotateBy(x: 0, y: CGFloat(-angle), z: 0, duration: durate)
        let rotateRight = SCNAction.rotateBy(x: 0, y: CGFloat(angle * 2), z: 0, duration: durate * 2)
        let rotateBack = SCNAction.rotateBy(x: 0, y: CGFloat(-angle), z: 0, duration: durate)
        rotateLeft.timingMode = .easeInEaseOut
        rotateRight.timingMode = .easeInEaseOut
        rotateBack.timingMode = .easeInEaseOut
        let swing = SCNAction.sequence([rotateLeft, rotateRight, rotateBack])
        let swingForever = SCNAction.repeatForever(swing)
        tanzakuNode.runAction(swingForever)
    }
    
    func getCameraPosition() -> SCNVector3? {
        if let currentFrame = sceneView.session.currentFrame {
            // ARカメラの位置（変換行列を取得）
            let cameraTransform = currentFrame.camera.transform
            let cameraPosition = SCNVector3(cameraTransform.columns.3.x,
                                            cameraTransform.columns.3.y,
                                            cameraTransform.columns.3.z)
            return cameraPosition
        }
        return nil
    }
}

// 拡張（SCNVector3.swiftなどに置いてもOK）
extension SCNVector3 {
    static func - (lhs: SCNVector3, rhs: SCNVector3) -> SCNVector3 {
        return SCNVector3(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z)
    }

    func length() -> Float {
        return sqrtf(x * x + y * y + z * z)
    }
}

extension UIColor {
    convenience init?(hex: String) {
        var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines)
        hexSanitized = hexSanitized.replacingOccurrences(of: "#", with: "")

        var rgb: UInt64 = 0
        guard Scanner(string: hexSanitized).scanHexInt64(&rgb) else { return nil }

        let r = CGFloat((rgb & 0xFF0000) >> 16) / 255
        let g = CGFloat((rgb & 0x00FF00) >> 8) / 255
        let b = CGFloat(rgb & 0x0000FF) / 255

        self.init(red: r, green: g, blue: b, alpha: 1.0)
    }
}

func colorFromCode(_ code: Int) -> UIColor {
    switch code {
    case 0: return .black
    case 1: return .systemRed
    case 2: return .systemBlue
    case 3: return .systemPink
    case 4: return .systemCyan
    case 5: return .systemIndigo
    case 6: return .systemPurple
    case 7: return .systemOrange
    case 8: return .systemYellow
    case 9: return .white
    default: return .systemGray // fallback
    }
}
