//
//  See LICENSE folder for this template’s licensing information.
//
//  Abstract:
//   playground ライブビューとコード間のメッセージハンドリング
//   playground BluetoothによるconnectionViewの表示

import UIKit
import SpriteKit
import Foundation
import Network
import PlaygroundSupport
import AVFoundation

protocol MoveSceneDelegate: AnyObject {
    func didReachGoal()
}

public enum TileType {
    case player  //スタート位置
    case goal  //ゴール位置
    case asteroid //障害物
    case warpIn(id: Int) //ワープイン
    case warpOut(id: Int) //ワープアウト
    case empty //空
    // タイルごとの画像名を返す
    var imageName: String {
        switch self {
        case .player: return "player"
        case .goal: return "goal"
        case .asteroid: return "asteroid"
        case .warpIn: return "warpIn"
        case .warpOut: return "warpOut"
        case .empty: return "empty" // 空のタイル
        }
    }
}

public class MoveViewController: UIViewController,PlaygroundLiveViewSafeAreaContainer, SetNameViewDelegate, MoveSceneDelegate {
    let map: [[TileType]] //マップデータ
    let maxFuel: Int //最大燃料
    private var cleard = false //クリアしたか？
    private var isGameOver = false // ゲームが終了したかどうかを判定するフラグ
    var soundButton: UIButton!
    var isSoundOn = true  // サウンドの状態（ON/OFF）
    private var mySKView = SKView()
    private var vstring = String()
    private var jewelType = Int() //宝石番号
    private var myScene = MoveScene()
    public var usernameLabel = UILabel()
    public var clrButton = UIButton()
    public var setUserButton = UIButton()
    private var addedLayers = [CAShapeLayer]()  //描画したシェイプを保持
    private var dropCounter = [0,0,0,0,0,0,0,0,0,0]  //各列のカウンター
    private var userName: String? = nil
    private var userNumber: String? = nil
    //private let tcpClient = TCPClient()
    private let url = URL(string: "https://isliceme01.stars.ne.jp/jewelDrop/session.php")!
    private var schoolId: String? = nil
    private var webMode: String? = nil
    private var currentSetNameView: SetNameView? = nil
    private var fuelCount = 0
    public var fuelLabel = UILabel()
    public var succeedMessage = "🎉おめでとう！ゴールできましたね！😀"
    // カスタムイニシャライザ
    public required init(map: [[TileType]], maxFuel: Int) {
        self.map = map
        self.maxFuel = maxFuel
        super.init(nibName: nil, bundle: nil)
    }
    
    public required init(coder aDecoder: NSCoder) {
        self.map = Array(repeating: Array(repeating: .empty, count: 10), count: 10)
        self.maxFuel = 0
        super.init(coder: aDecoder)!
    }
    
    public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        self.map = Array(repeating: Array(repeating: .empty, count: 10), count: 10)
        self.maxFuel = 0
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

    override public func viewDidLoad() {
        super.viewDidLoad()
        // PlaygroundKeyValueStoreからSchoolIdを取得
        if let keyValue = PlaygroundKeyValueStore.current["schoolId"],
           case .string(let storedSchoolId) = keyValue {
            schoolId = storedSchoolId
        } else {
            schoolId = nil
        }
        
        // PlaygroundKeyValueStoreからWebModeを取得
        if let keyValue = PlaygroundKeyValueStore.current["webMode"],
           case .string(let storedWebMode) = keyValue {
            webMode = storedWebMode
        } else {
            webMode = nil
        }

        // PlaygroundKeyValueStoreからユーザー名を取得
        if let keyValue = PlaygroundKeyValueStore.current["userName"],
            case .string(let storedUserName) = keyValue {
            userName = storedUserName
        } else {
            userName = nil
        }
        
        // PlaygroundKeyValueStoreから番号を取得
        if let keyValue = PlaygroundKeyValueStore.current["userNumber"],
            case .string(let storedNumber) = keyValue {
            userNumber = storedNumber
        } else {
            userNumber = nil
        }
        
        //クライアントの開始
        //tcpClient.start()
        
        jewelType = 1
        view.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
        // disable auto layout
        view.translatesAutoresizingMaskIntoConstraints = false
        
       //ビューを配置
        mySKView.isUserInteractionEnabled = true
        mySKView.clipsToBounds = true //はみ出さない様にする。

        mySKView.layer.cornerRadius = 0
        //mySKView.showsFPS = true
        //mySKView.showsNodeCount = true
        mySKView.translatesAutoresizingMaskIntoConstraints  = false
        mySKView.frame.size = CGSize(width:200.0, height:200.0)
        myScene = MoveScene(size: mySKView.frame.size)
        myScene.scaleMode = .aspectFit
        myScene.moveSceneDelegate = self //シーンからの呼び出しを受ける。
        mySKView.allowsTransparency = true
        mySKView.presentScene(myScene)
        view.addSubview(mySKView)
        // マップのタイルを配置
        let mapHeight = map.count
        for y in 0..<mapHeight {
            for x in 0..<map[y].count {
                let tile = map[y][x]
                switch tile {
                case .empty:
                    continue
                case .warpIn(let id), .warpOut(let id):
                    let adjustedY = mapHeight - y // Y座標を上下反転（SpriteKitの座標系に合わせる）
                    myScene.placeNode(x + 1, adjustedY, imageName: tile.imageName, warpId: id)
                default:
                    let adjustedY = mapHeight - y // Y座標を上下反転（SpriteKitの座標系に合わせる）
                    myScene.placeNode(x + 1, adjustedY, imageName: tile.imageName)
                }
            }
        }
         // ボタンの位置とサイズを設定
        clrButton.frame = CGRect(x:20, y:80,
                        width:120, height:30)
         // ボタンのタイトルを設定
        clrButton.setTitle("リセット", for:UIControl.State.normal)
         // タイトルの色
        clrButton.setTitleColor(UIColor.blue, for: .normal)
         // ボタンのフォントサイズ
        clrButton.titleLabel?.font =  UIFont.systemFont(ofSize: 16)
         // 背景色
        clrButton.backgroundColor = UIColor.init(
            red:0.9, green: 0.9, blue: 0.9, alpha: 0.5)
        clrButton.layer.cornerRadius = 5
         // タップされたときのaction
        clrButton.addTarget(self,
                            action: #selector(self.buttonTapped(sender:)),
                for: .touchUpInside)
         // Viewにボタンを追加
        self.view.addSubview(clrButton)
        clrButton.isEnabled = false
        // ボタンの位置とサイズを設定
        setUserButton.frame = CGRect(x:160, y:80,
                       width:120, height:30)
        // ボタンのタイトルを設定
        setUserButton.setTitle("ユーザー設定", for:UIControl.State.normal)
        // タイトルの色
        setUserButton.setTitleColor(UIColor.blue, for: .normal)
        // ボタンのフォントサイズ
        setUserButton.titleLabel?.font =  UIFont.systemFont(ofSize: 16)
        // 背景色
        setUserButton.backgroundColor = UIColor.init(
           red:0.9, green: 0.9, blue: 0.9, alpha: 0.5)
        setUserButton.layer.cornerRadius = 5
        // タップされたときのaction
        setUserButton.addTarget(self,
                           action: #selector(self.showSetNameView),
               for: .touchUpInside)
        // Viewにボタンを追加
        setUserButton.isEnabled = false
        setUserButton.isHidden = true
        self.view.addSubview(setUserButton)
        
        //ユーザー名ラベルの位置とサイズを設定
        usernameLabel.frame = CGRect(x:150, y:80, width:400, height:30)
        usernameLabel.font = UIFont.systemFont(ofSize: 20)
        usernameLabel.text = [userNumber, userName].compactMap { $0 }.joined(separator: ":")
        self.view.addSubview(usernameLabel)
        
        //燃料ラベルの位置とサイズを設定
        fuelLabel.frame = CGRect(x:150, y:80, width:400, height:30)
        fuelLabel.font = UIFont.systemFont(ofSize: 20)
        let fuelEmoji = String(repeating: "🔥", count: maxFuel)
        fuelLabel.text = "燃料(\(maxFuel)):\(fuelEmoji)"
        self.view.addSubview(fuelLabel)
        
        //BGMサウンドON/OFFボタンを設定
        soundButton = UIButton(type: .system)
        soundButton.setTitle("BGM:🔈", for: .normal)
        soundButton.titleLabel?.font = UIFont.systemFont(ofSize: 20)
        soundButton.addTarget(self, action: #selector(toggleSound), for: .touchUpInside)
        soundButton.tintColor = .label
        soundButton.contentHorizontalAlignment = .left
        view.addSubview(soundButton)

        clrButton.translatesAutoresizingMaskIntoConstraints  = false
        setUserButton.translatesAutoresizingMaskIntoConstraints  = false
        usernameLabel.translatesAutoresizingMaskIntoConstraints  = false
        fuelLabel.translatesAutoresizingMaskIntoConstraints  = false
        soundButton.translatesAutoresizingMaskIntoConstraints  = false
        
        NSLayoutConstraint.activate([
            setUserButton.leadingAnchor.constraint(equalTo: liveViewSafeAreaGuide.leadingAnchor,constant: 20.0),
            setUserButton.topAnchor.constraint(equalTo: liveViewSafeAreaGuide.topAnchor,constant: 10.0),
            setUserButton.heightAnchor.constraint(equalToConstant: 30.0),
            setUserButton.widthAnchor.constraint(equalToConstant: 100.0),
            
            clrButton.trailingAnchor.constraint(equalTo: liveViewSafeAreaGuide.trailingAnchor,constant: -20.0),
            clrButton.topAnchor.constraint(equalTo: liveViewSafeAreaGuide.topAnchor,constant: 10.0),
            clrButton.heightAnchor.constraint(equalToConstant: 30.0),
            clrButton.widthAnchor.constraint(equalToConstant: 100.0),
            
            usernameLabel.leadingAnchor.constraint(equalTo: setUserButton.trailingAnchor,constant: 20.0),
            usernameLabel.trailingAnchor.constraint(equalTo: clrButton.leadingAnchor, constant: -20),
            usernameLabel.topAnchor.constraint(equalTo: liveViewSafeAreaGuide.topAnchor,constant: 10.0),
            usernameLabel.heightAnchor.constraint(equalToConstant: 30.0),

            mySKView.leadingAnchor.constraint(equalTo: liveViewSafeAreaGuide.leadingAnchor,constant: 20.0),
            mySKView.trailingAnchor.constraint(equalTo: liveViewSafeAreaGuide.trailingAnchor, constant: -20.0),
            mySKView.topAnchor.constraint(equalTo: liveViewSafeAreaGuide.topAnchor, constant: 50.0),
            mySKView.bottomAnchor.constraint(equalTo: liveViewSafeAreaGuide.bottomAnchor, constant: -50),
            
            fuelLabel.leadingAnchor.constraint(equalTo: liveViewSafeAreaGuide.leadingAnchor,constant: 20.0),
            fuelLabel.trailingAnchor.constraint(equalTo: liveViewSafeAreaGuide.trailingAnchor, constant: -20.0),
            fuelLabel.topAnchor.constraint(equalTo: mySKView.bottomAnchor,constant: 5.0),
            fuelLabel.heightAnchor.constraint(equalToConstant: 20.0),
            
            soundButton.leadingAnchor.constraint(equalTo: liveViewSafeAreaGuide.leadingAnchor,constant: 20.0),
            soundButton.widthAnchor.constraint(equalToConstant: 100.0),
            soundButton.topAnchor.constraint(equalTo: fuelLabel.bottomAnchor,constant: 5.0),
            soundButton.heightAnchor.constraint(equalToConstant: 20.0)
            ])
    }
    
    override public func viewWillAppear(_ animated: Bool) {
    }
    
    @objc func showSetNameView() {
        // すでに SetNameView が表示されているかどうかを確認
        if currentSetNameView != nil {
            return
        }
        
        let setNameView = SetNameView()
        setNameView.delegate = self // デリゲートを設定
        setNameView.translatesAutoresizingMaskIntoConstraints = false
        // SetNameView を現在のプロパティに保持
        currentSetNameView = setNameView
        
        self.view.addSubview(setNameView)
        
        NSLayoutConstraint.activate([
            setNameView.leadingAnchor.constraint(equalTo: liveViewSafeAreaGuide.leadingAnchor,constant: 40.0),
            setNameView.trailingAnchor.constraint(equalTo: liveViewSafeAreaGuide.trailingAnchor, constant: -40.0),
            setNameView.topAnchor.constraint(equalTo: liveViewSafeAreaGuide.topAnchor, constant: 70.0),
            setNameView.bottomAnchor.constraint(equalTo: liveViewSafeAreaGuide.bottomAnchor, constant: -70)
        ])
    }
    
    @objc func toggleSound() {
        isSoundOn.toggle()
        // MoveScene のメソッドを直接呼び出して音をON/OFF
        myScene.toggleMusic(isOn: isSoundOn)
        // ボタンのアイコンを変更
        let icon = isSoundOn ? "BGM:🔈" : "BGM:🔇"
        soundButton.setTitle(icon, for: .normal)
    }
    
    func didSaveSettings(userName: String?, userNumber: String?) {
        self.userName = userName
        self.userNumber = userNumber
        usernameLabel.text = [userNumber, userName].compactMap { $0 }.joined(separator: ":")
        currentSetNameView?.removeFromSuperview()
        currentSetNameView = nil
    }
    
    func didCloseSetNameView() {
        // `SetNameView` を削除
        currentSetNameView?.removeFromSuperview()
        currentSetNameView = nil
    }
    
    @objc func buttonTapped(sender : Any) {
        //リセット
        isGameOver = false
        cleard = false
        myScene.clear()
        fuelCount = 0
        let fuelEmoji = String(repeating: "🔥", count: maxFuel)
        fuelLabel.text = "燃料(\(maxFuel)):\(fuelEmoji)"
        // マップのタイルを配置
        let mapHeight = map.count
        for y in 0..<mapHeight {
            for x in 0..<map[y].count {
                let tile = map[y][x]
                switch tile {
                case .empty:
                    continue
                case .asteroid:
                    continue
                case .warpIn(let id), .warpOut(let id):
                    let adjustedY = mapHeight - y // Y座標を上下反転（SpriteKitの座標系に合わせる）
                    myScene.placeNode(x + 1, adjustedY, imageName: tile.imageName, warpId: id)
                default:
                    let adjustedY = mapHeight - y // Y座標を上下反転（SpriteKitの座標系に合わせる）
                    myScene.placeNode(x + 1, adjustedY, imageName: tile.imageName)
                }
            }
        }
    }
    
    // ゴール到達時の処理
    func didReachGoal() {
        //buttonTapped(sender: self)
        cleard = true
        PlaygroundPage.current.assessmentStatus = .pass(message: succeedMessage)
    }
    
}


extension MoveViewController: PlaygroundLiveViewMessageHandler {
    //Playgroundページからメッセージを受け取る際の処理。
    public func receive(_ message: PlaygroundValue) {
        clrButton.isEnabled = false
        if case let .string(text) = message {
            if(text == "clear") { //クリア命令
                //全消し
                buttonTapped(sender: self)
                return
            }
            
            let arr:[String] = text.components(separatedBy: " ")
            
            var codetext = ""
            if(arr[0] == "message") {
                let codeText = PlaygroundPage.current.text
                // 取得した文字列から、ユーザー編集したものだけを取り出して出力
                let pattern = #"//#-editable-code\n([\s\S]*?)\n//#-end-editable-code"#
                do {
                    let regex = try NSRegularExpression(pattern: pattern, options: [])
                    let nsRange = NSRange(codeText.startIndex..<codeText.endIndex, in: codeText)
                    let matches = regex.matches(in: codeText, options: [], range: nsRange)
                    // マッチした内容を取り出す
                    for match in matches {
                        if let range = Range(match.range(at: 1), in: codeText) {
                            codetext += String(codeText[range]) + "\n"
                        }
                    }
                } catch {
                    codetext = "\n"
                }
                let message = (userNumber ?? "-") + "," + (userName ?? "未設定") + "," + text.suffix(text.count - 8)
                
                if (webMode == "Off") { //Bonjour送信の場合
                    let tcpClient = TCPClient()
                    // サービスの開始
                    tcpClient.start()
                    // 接続が確立された後にメッセージを送信するようにコールバックを設定
                    tcpClient.onConnectionReady = {
                        let messagedict: [String: String] = [
                            "message": message,
                            "code": codetext
                        ]
                        tcpClient.send(messageDict: messagedict)
                    }
                } else if (webMode == "On") { //Web送信の場合
                    //web送信の場合
                    let httpSend = HTTPSend(url: url)
                    httpSend.sendMessage(messageText: message, codeText:codetext, schoolId: schoolId ?? "") { result in
                        switch result {
                        case .success:
                            print("Message sent successfully")
                        case .failure(let error):
                            print("Failed to send message: \(error.localizedDescription)")
                        }
                    }
                    return
                }
            }
            
            if (arr[0] == "finished") {
                if !cleard && !isGameOver {
                    PlaygroundPage.current.assessmentStatus = .fail(hints: ["🤔ざんねん！もういちどチャレンジしてみましょう！"], solution: nil)
                }
            }
            
            if (arr[0] == "successmessage") {
                if arr.count > 1 {
                    succeedMessage = arr[1]
                }
            }
            
            
            if(arr[0] == "left" || arr[0] == "right" || arr[0] == "move" || arr[0] == "moveLeft" || arr[0] == "moveRight") {
                if isGameOver || cleard { return }
                fuelCount += 1
                let remainingFuel = maxFuel - fuelCount
                if remainingFuel < 0 {
                    isGameOver = true  // ゲームオーバーフラグを立てる
                    PlaygroundPage.current.assessmentStatus = .fail(hints: ["😨途中で燃料がなくなってしまいました。"], solution: nil)
                    return
                }
                // 燃料の表示を更新（負の値にならないよう max を使う）
                let fuelEmoji = String(repeating: "🔥", count: max(remainingFuel, 0))
                fuelLabel.text = "燃料(\(remainingFuel)):\(fuelEmoji)"
                if arr[0] == "left" {
                    myScene.playerLeft()
                } else if arr[0] == "right" {
                    myScene.playerRight()
                } else if arr[0] == "move" {
                    myScene.playerForward()
                } else if arr[0] == "moveLeft" {
                    myScene.playerForward(thrusterFailure: .left)
                } else if arr[0] == "moveRight" {
                    myScene.playerForward(thrusterFailure: .right)
                } else {
                    return
                }
            }
            if(arr.count == 3) {
                if(arr[0] == "place") {
                    myScene.placeNode(Int(arr[1])!, Int(arr[2])!, imageName: "asteroid01.png")
                }
            }
        }
    }
    
    public func liveViewMessageConnectionOpened() {
        clrButton.isEnabled = false
        mySKView.isUserInteractionEnabled = false
        // Implement this method to be notified when the live view message connection is opened.
        // The connection will be opened when the process running Contents.swift starts running and listening for messages.
    }
    
    public func liveViewMessageConnectionClosed() {
        clrButton.isEnabled = true
        mySKView.isUserInteractionEnabled = true
        // Implement this method to be notified when the live view message connection is closed.
        // The connection will be closed when the process running Contents.swift exits and is no longer listening for messages.
        // This happens when the user's code naturally finishes running, if the user presses Stop, or if there is a crash.
    }
}


