//
//  SharingData.swift
//  forShip
//
//  Created by Mamoru Sugita on 2023/10/20.
//
import Foundation
import CoreLocation

class SharingData{

    static var my = My()
    class My: ObservableObject {
        @Published var id: Int = 0
        @Published var shipId: Int = 0
        @Published var shipName: String = ""
        @Published var imo: Int = 0
        @Published var mmsi: Int = 0
        @Published var isUpDate: Bool = false
        @Published var isFuelSwitchTask: Bool = false
        @Published var isNga: Bool = false
        @Published var isCommunication: Bool = false
        @Published var isManual: Bool = false

        @Published var ecaStatus: EcaState?

        var manualUrls: [ResGetManualUrl] = []
    }

    static var location = Location()
    class Location: ObservableObject {
        @Published var location: CLLocationCoordinate2D? = .init(latitude: 0, longitude: 0)
        @Published var gps: CLLocationCoordinate2D? = nil
        @Published var server: CLLocationCoordinate2D? = nil

        @Published var status: ShipAlert = ShipAlert.Normal
        @Published var totalRmsAlarm: AlertStatusType = AlertStatusType.Normal
        @Published var speed: Double = 0.0
        @Published var course: Double = 0.0
        @Published var heading: Double = 0.0
        @Published var dataTime: String = "" //2023-11-02T05:25:49.4362123Z

        @Published var focusOwnShip: Bool = false

        func setLocation(){
            if Preferences.LocationType == 0 {
                self.location = self.gps
            } else {
                self.location = self.server
            }
        }

        func setShipStatus(status: Int) -> ShipAlert {
            var shipAlert = ShipAlert.Normal

            switch status {
            case -1:
                shipAlert = ShipAlert.Offline
            case 0:
                shipAlert = ShipAlert.Unknown
            case 1:
                shipAlert = ShipAlert.Normal
            case 2:
                shipAlert = ShipAlert.Caution
            case 3:
                shipAlert = ShipAlert.Warning
            case 4:
                shipAlert = ShipAlert.Alarm
            case 5:
                shipAlert = ShipAlert.Emergency
            case 6:
                shipAlert = ShipAlert.NecstEmergency
            default:
                shipAlert = ShipAlert.Unknown
            }

            return shipAlert
        }

        func setTotalRmsAlarm(alarm: Int) -> AlertStatusType {
            var rmsAlarm = AlertStatusType.Normal

            switch alarm {
            case 0:
                rmsAlarm = AlertStatusType.Unknown
            case 1:
                rmsAlarm = AlertStatusType.Normal
            case 2:
                rmsAlarm = AlertStatusType.Caution
            case 3:
                rmsAlarm = AlertStatusType.Warning
            case 4:
                rmsAlarm = AlertStatusType.Alarm
            case 5:
                rmsAlarm = AlertStatusType.Emergency
            default:
                rmsAlarm = AlertStatusType.Unknown
            }

            return rmsAlarm
        }

        func reset() {
            speed = 0.0
            course = 0.0
            heading = 0.0

            location = nil
        }
    }

    static var map = Map()
    class Map: ObservableObject {
        @Published var wayPoints: [CLLocationCoordinate2D] = []
        @Published var legLine: [CLLocationCoordinate2D] = []
        @Published var portLine: [CLLocationCoordinate2D] = []
        @Published var starboardLine: [CLLocationCoordinate2D] = []
        @Published var isMapFree: Bool = false
    }

    /**
     * Eca
     */
    static var eca = Eca()
    class Eca: ObservableObject{
        @Published var ecaArea: Dictionary<Int, RegisteredEca> = [:]
        @Published var focusEca: Int? = nil
        @Published var isShowEcaAlert: Bool = false

        func setEcaArea(key: Int, value: RegisteredEca) {
            ecaArea.updateValue(value, forKey: key)
        }

        func editEcaArea(key: Int, value: RegisteredEca, type: EcaOperation) {
            let setEcaArea = SetEcaArea()
            var task = ReqTaskList(Id: value.areaId)

            switch type {
            case EcaOperation.Running:
                task.id = UUID().uuidString
                task.areaId = value.areaId
                task.userName = Preferences.UserName
                task.taskName = value.name
                task.noticeRange = value.swNotice
                task.startRange = value.swStart
                task.finishRange = value.swFinish
                task.status = serverRunning
                task.lastUpdateTime = DateTextLib.Date2ISO8601Text(Date())
                setEcaArea.start(eca: task)
            case EcaOperation.Insert:
                task.id = UUID().uuidString
                task.areaId = value.areaId
                task.userName = Preferences.UserName
                task.taskName = value.name
                task.noticeRange = value.swNotice
                task.startRange = value.swStart
                task.finishRange = value.swFinish
                task.status = serverRegister
                task.lastUpdateTime = DateTextLib.Date2ISO8601Text(Date())
                setEcaArea.start(eca: task)
            case EcaOperation.Delete:
                let deleteEcaArea = DeleteEcaArea()
                deleteEcaArea.start(ecaId: value.areaId)
            case EcaOperation.Notice:
                task.id = value.id
                task.areaId = value.areaId
                task.userName = value.userName
                task.taskName = Preferences.UserName
                task.noticeRange = value.swNotice
                task.startRange = value.swStart
                task.finishRange = value.swFinish
                if value.isEnable && value.isRunning {
                    task.status = setEcaStatus(eca: value)
                }
                task.lastUpdateTime = DateTextLib.Date2ISO8601Text(Date())
                setEcaArea.start(eca: task)
            case EcaOperation.Start:
                task.id = value.id
                task.areaId = value.areaId
                task.userName = value.userName
                task.taskName = Preferences.UserName
                task.noticeRange = value.swNotice
                task.startRange = value.swStart
                task.finishRange = value.swFinish
                if value.isEnable && value.isRunning {
                    task.status = setEcaStatus(eca: value)
                }
                task.lastUpdateTime = DateTextLib.Date2ISO8601Text(Date())
                setEcaArea.start(eca: task)
            case EcaOperation.Finish:
                task.id = value.id
                task.areaId = value.areaId
                task.userName = Preferences.UserName
                task.taskName = value.name
                task.noticeRange = value.swNotice
                task.startRange = value.swStart
                task.finishRange = value.swFinish
                if value.isEnable {
                    task.status = setEcaStatus(eca: value)
                }
                task.lastUpdateTime = DateTextLib.Date2ISO8601Text(Date())
                setEcaArea.start(eca: task)
            case EcaOperation.End:
                task.id = value.id
                task.areaId = value.areaId
                task.userName = Preferences.UserName
                task.taskName = value.name
                task.noticeRange = value.swNotice
                task.startRange = value.swStart
                task.finishRange = value.swFinish
                if value.isEnable {
                    task.status = setEcaStatus(eca: value)
                }
                task.lastUpdateTime = DateTextLib.Date2ISO8601Text(Date())
                setEcaArea.start(eca: task)
            case EcaOperation.Incomplete:
                task.id = value.id
                task.areaId = value.areaId
                task.userName = Preferences.UserName
                task.taskName = value.name
                task.noticeRange = value.swNotice
                task.startRange = value.swStart
                task.finishRange = value.swFinish
                if value.isEnable {
                    task.status = setEcaStatus(eca: value)
                }
                task.lastUpdateTime = DateTextLib.Date2ISO8601Text(Date())
                setEcaArea.start(eca: task)
            case EcaOperation.Cancel:
                task.id = value.id
                task.areaId = value.areaId
                task.userName = Preferences.UserName
                task.taskName = value.name
                task.noticeRange = value.swNotice
                task.startRange = value.swStart
                task.finishRange = value.swFinish
                if value.isEnable {
                    task.status = setEcaStatus(eca: value)
                }
                task.lastUpdateTime = DateTextLib.Date2ISO8601Text(Date())
                setEcaArea.start(eca: task)
            case EcaOperation.Change:
                task.id = value.id
                task.areaId = value.areaId
                task.userName = Preferences.UserName
                task.taskName = value.name
                task.noticeRange = value.swNotice
                task.startRange = value.swStart
                task.finishRange = value.swFinish
                if value.isEnable && value.isRunning {
                    task.status = setEcaStatus(eca: value)
                }
                task.lastUpdateTime = DateTextLib.Date2ISO8601Text(Date())
                setEcaArea.start(eca: task)
            }
            ecaArea.updateValue(value, forKey: key)
        }

        private func setEcaStatus(eca: RegisteredEca) -> Int {
            var state = serverRegister
            switch eca.status {
            case EcaState.running:
                state = serverRunning
            case EcaState.noticePass:
                state = serverNoticePass
            case EcaState.startPass:
                state = serverStartPass
            case EcaState.finishPass:
                state = serverFinishPass
            case EcaState.end:
                state = serverEnd
            case EcaState.incomplete:
                state = serverIncomplete
            case EcaState.cancel:
                state = serverCancel
            default:
                state = serverRegister
            }

            return state
        }
    }

    /**
     * Nga Area
     */
    static var nga = Nga()
    class Nga: ObservableObject {
        @Published var ngaArea: Dictionary<UUID, RegisteredNga> = [:]
        @Published var editType = EditNgaType.nonEdit
        @Published var editNga: RegisteredNga? = nil
        @Published var moveNga: RegisteredNga? = nil
        @Published var focusNga: String? = nil
        @Published var targetLocation: CLLocationCoordinate2D? = nil    //UserMark.movePointLocation

        @Published var selectPoint: Int?

        func setNgaArea(key: UUID, value: RegisteredNga) {
            ngaArea.updateValue(value, forKey: key)
        }

        func deleteNgaArea(key: UUID) {
            ngaArea.removeValue(forKey: key)
        }

        func editNgaArea(value: RegisteredNga, type: NgaOperation) {
            let setNgaArea = SetNgaArea()
            var task = ReqNgaList(Id: value.areaId.uuidString)

            switch type {
            case NgaOperation.Change:
                task.id = value.areaId.uuidString
                task.name = value.name
                task.enabled = value.isRunning
                task.lock = value.isLock
                for point in value.points {
                    let position = points(lat: point.latitude, lon: point.longitude)
                    task.geometry.append(position)
                }
                setNgaArea.start(nga: task)
                ngaArea.updateValue(value, forKey: value.areaId)
                break
            case NgaOperation.Delete:
                let deleteNgaArea = DeleteNgaArea()
                deleteNgaArea.start(areaId: value.areaId.uuidString)
                ngaArea.removeValue(forKey: value.areaId)
                break
            case NgaOperation.Running:
                task.id = value.areaId.uuidString
                task.name = value.name
                task.enabled = value.isRunning
                task.lock = value.isLock
                for point in value.points {
                    let position = points(lat: point.latitude, lon: point.longitude)
                    task.geometry.append(position)
                }
                setNgaArea.start(nga: task)
                ngaArea.updateValue(value, forKey: value.areaId)
                break
            case NgaOperation.Passing:
                ngaArea.updateValue(value, forKey: value.areaId)
                break
            case NgaOperation.Cancel:
                task.id = value.areaId.uuidString
                task.name = value.name
                task.enabled = value.isRunning
                task.lock = value.isLock
                for point in value.points {
                    let position = points(lat: point.latitude, lon: point.longitude)
                    task.geometry.append(position)
                }
                setNgaArea.start(nga: task)
                ngaArea.updateValue(value, forKey: value.areaId)
                break
            }
        }
    }

    static var message = Message()
    class Message: ObservableObject {
        @Published var mode: Bool = false   // false:通常 , true:Warning中
        @Published var messages: [ChatMessage] = []
        @Published var users: [ChatUser] = []
        @Published var viewCnt: Int = 0        //未読数
        @Published var sendInf: Bool = false    //送信状態

        func changeMode(){
            self.mode.toggle()
        }
    }

    static var information = Information()
    class Information: ObservableObject {
        @Published var content: [ResInformation] = []
    }

    static var pushHistory = PushHistory()
    class PushHistory: ObservableObject{
        @Published var pushHistoryData: Dictionary<Int, ResPushHistory> = [:]
        @Published var focusPushHistory: Int? = nil
        @Published var viewCnt: Int = 0        //未読数

        func setPushHistory(key: Int, value: ResPushHistory) {
            pushHistoryData.updateValue(value, forKey: key)
        }
    }

    static var noticeInformation = NoticeInformation()
    class NoticeInformation: ObservableObject {
    }
}
