import SwiftUI
import Combine
import Speech
import AVFoundation
import UIKit

enum MediaInputType {
    case none
    case camera
    case photoLibrary
    case fileImport
}

class ChatInputViewModel: ObservableObject {
    @Published var failedUploadImage: ReqUploadImage? = nil
    @Published var isRetryDialogPresented = false
    @Published var isSignalrRestart = false
    @Published var isRecording = false
    @Published var isChatAlert = false
    @Published var inputText = ""
    @Published var textViewHeight: CGFloat = 40
    @Published var tempId: String = ""
    @Published var mediaInputType: MediaInputType = .none
    @Published var isImagePickerPresented = false
    @Published var isFileImporterPresented = false

    @Published var isKeyboardFocused: Bool = false
    @Published var isUploadingDialogPresented: Bool = false
    @Published var isFocus: Double = 0.0

    private let sessionUploadImage = SessionUploadImage()

    //MARK: - メディア入力
    func handleMediaInput(type: MediaInputType) {
        self.mediaInputType = type
        if type == .camera || type == .photoLibrary {
            self.isImagePickerPresented = true
        } else if type == .fileImport {
            self.isFileImporterPresented = true
        }
    }

    // MARK: - Send Chat Message
    func sendChatMessage() {
        guard !SharingData.message.sendInf else { return }

        isRecording = false

        SignalR().chatMessage(message: inputText, completion: responseChatMessage)
        SharingData.message.sendInf = true

        DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
            self.restartChatMessage()
        }
    }

    // MARK: - Chat Response
    private func responseChatMessage(error: Error?) {
        SharingData.message.sendInf = false

        if let error = error {
            print("Chat error: \(error)")
            isChatAlert = true
        } else {
            isKeyboardFocused = false
            inputText = ""
        }
    }

    // MARK: - Restart Chat if No Response
    private func restartChatMessage() {
        if SharingData.message.sendInf {
            SignalR().stopConnection()
            DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
                self.isSignalrRestart = true
            }
        }
    }

    //MARK: - テキスト高さ
    func recalculateHeight() {
        let textView = UITextView()
        textView.text = inputText
        textView.font = UIFont.preferredFont(forTextStyle: .body)
        let fixedWidth = UIScreen.main.bounds.width - 40 // 適宜調整
        let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
        textViewHeight = max(newSize.height, 40) // 最低高さを40に設定
    }

    // MARK: - Send Chat Image
    func sendChatImage(_ uploadImage: ReqUploadImage) {
        Task {
            do {
                isUploadingDialogPresented = true
                let response = try await sessionUploadImage.requestUploadImage(uploadImage)
                print(debug: "Upload success: \(response)")

                let serverSession = ServerSession()
                _ = serverSession.fromJSON(resultData: response, resltType: ResLogin.self)

                sessionUploadImage.progress = 0.0 // 完了後リセット
                isUploadingDialogPresented = false
            } catch {
                print(debug: "Upload failed: \(error)")
                sessionUploadImage.progress = 0.0 // エラー時もリセット

                isUploadingDialogPresented = false
                failedUploadImage = uploadImage
                isRetryDialogPresented = true
            }
        }
    }

    //MARK: - Send Chat Video
    func sendChatVideo(_ uploadVideo: ReqUploadImage) {
        Task {
            do {
                isUploadingDialogPresented = true
                let response = try await SessionUploadImage.OnlyOne.requestUploadVideo(uploadVideo)
                print(debug: "Video upload success: \(response)")

                let serverSession = ServerSession()
                _ = serverSession.fromJSON(resultData: response, resltType: ResLogin.self)

                SessionUploadImage.OnlyOne.progress = 0.0
                isUploadingDialogPresented = false
            } catch {
                print(debug: "Video upload failed: \(error)")
                SessionUploadImage.OnlyOne.progress = 0.0

                isUploadingDialogPresented = false
                failedUploadImage = uploadVideo
                isRetryDialogPresented = true
            }
        }
    }

    // MARK: - ローカル画像を一時保存してURLを取得 (静止画)
    func saveImageToTemporaryDirectory(_ image: UIImage) -> String? {
        let fileName = UUID().uuidString + ".jpg"
        let tempDir = FileManager.default.temporaryDirectory
        let fileURL = tempDir.appendingPathComponent(fileName)

        guard let data = image.jpegData(compressionQuality: 0.8) else {
            print(debug: "Image JPEG conversion failed")
            return nil
        }

        do {
            try data.write(to: fileURL)
            return fileURL.absoluteString
        } catch {
            print(debug: "Image JPEG conversion failed: \(error.localizedDescription)")
            return nil
        }
    }

    //MARK: - 送信前に送信画像をテンポラリに入れる
    func sendImageToTemporary(_ image: UIImage) {
        if let localURL = saveImageToTemporaryDirectory(image),
        let jpegData = image.jpegData(compressionQuality: 1.0) {
            tempId = UUID().uuidString
            let viewer = Viewer(
                time: DateTextLib.Date2ISO8601Text(Date()),
                location: 2,
                id: "",
                name: ""
            )
            let tempMessage = ChatMessage(
                shipId: Preferences.shipId,
                messageId: tempId,
                type: 2,
                time: DateTextLib.Date2ISO8601Text(Date()),
                location: 2,
                from: Preferences.UserName,
                fromId: String(SharingData.my.id),
                mode: SharingData.message.mode ? 1 : 0,
                message: localURL,
                stampId: 0,
                viewer: [viewer]
            )
            SharingData.message.messages.append(tempMessage)

            let uploadImage = ReqUploadImage(
                shipId: Preferences.shipId,
                messageId: tempId,
                location: 2,
                from: Preferences.UserName,
                fromId: String(SharingData.my.id),
                files: jpegData
            )

            sendChatImage(uploadImage)
        }
    }

    // MARK: - ローカル画像を一時保存してURLを取得 (動画)
    func saveVideoToTemporaryDirectory(_ data: Data) -> URL? {
        let fileName = UUID().uuidString + ".mp4"
        let tempDir = FileManager.default.temporaryDirectory
        let fileURL = tempDir.appendingPathComponent(fileName)

        do {
            try data.write(to: fileURL)
            return fileURL
        } catch {
            print(debug: "Video save failed: \(error.localizedDescription)")
            return nil
        }
    }

    //MARK: - 動画データからサムネイル画像を生成する
    func generateThumbnail(from videoURL: URL, at time: CMTime = CMTime(seconds: 1.0, preferredTimescale: 600)) -> UIImage? {
        let asset = AVAsset(url: videoURL)
        let imageGenerator = AVAssetImageGenerator(asset: asset)
        imageGenerator.appliesPreferredTrackTransform = true

        do {
            let cgImage = try imageGenerator.copyCGImage(at: time, actualTime: nil)
            return UIImage(cgImage: cgImage)
        } catch {
            print("サムネイル生成失敗: \(error.localizedDescription)")
            return nil
        }
    }

    //MARK: - 送信前に送信動画をテンポラリに入れる
    func sendVideoToTemporary(_ data: Data) {
        if let videoURL = saveVideoToTemporaryDirectory(data),
        let image = generateThumbnail(from: videoURL),
        let localURL = saveImageToTemporaryDirectory(image) {
            tempId = UUID().uuidString
            let viewer = Viewer(
                time: DateTextLib.Date2ISO8601Text(Date()),
                location: 2,
                id: "",
                name: ""
            )
            let tempMessage = ChatMessage(
                shipId: Preferences.shipId,
                messageId: tempId,
                type: 3, // 動画タイプ
                time: DateTextLib.Date2ISO8601Text(Date()),
                location: 2,
                from: Preferences.UserName,
                fromId: String(SharingData.my.id),
                mode: SharingData.message.mode ? 1 : 0,
                message: localURL,
//                videoUrl: videoURL.absoluteString,
                stampId: 0,
                viewer: [viewer]
            )
            SharingData.message.messages.append(tempMessage)

            let uploadVideo = ReqUploadImage(
                shipId: Preferences.shipId,
                messageId: tempId,
                location: 2,
                from: Preferences.UserName,
                fromId: String(SharingData.my.id),
                files: data
            )

            sendChatVideo(uploadVideo)
        }
    }
}
