//
//  AuditionRoleDetailViewModel.swift
//  SodaLive
//
//  Created by klaus on 1/6/25.
//

import Foundation
import Moya
import Combine

final class AuditionRoleDetailViewModel: ObservableObject {
    
    private let repository = AuditionRepository()
    private var subscription = Set<AnyCancellable>()
    
    @Published var errorMessage = ""
    @Published var isShowPopup = false
    @Published var isLoading = false
    
    @Published var totalCount = 0
    @Published var applicantList = [GetAuditionRoleApplicantItem]()
    
    @Published var name = "보이스온"
    @Published var auditionRoleDetail: GetAuditionRoleDetailResponse? = nil
    
    @Published var sortType = AuditionApplicantSortType.NEWEST {
        didSet {
            page = 1
            isLast = false
            getAuditionRoleDetail()
        }
    }
    
    @Published var fileName = ""
    @Published var soundData: Data? = nil
    @Published var phoneNumber = ""
    
    var page = 1
    var isLast = false
    private var pageSize = 10
    
    var auditionRoleId = -1 {
        didSet {
            if auditionRoleId > 0 {
                getAuditionRoleDetail()
            } else {
                onFailure()
            }
        }
    }
    
    var onFailure: () -> Void = {}
    
    func getAuditionRoleDetail() {
        isLoading = true
        
        let auditionRoleDetail = repository.getAuditionRoleDetail(auditionRoleId: auditionRoleId)
        let auditionApplicantList = repository.getAuditionApplicantList(auditionRoleId: auditionRoleId, sortType: sortType, page: page, size: pageSize)
        
        Publishers
            .CombineLatest(auditionRoleDetail, auditionApplicantList)
            .sink { result in
                switch result {
                case .finished:
                    DEBUG_LOG("finish")
                case .failure(let error):
                    ERROR_LOG(error.localizedDescription)
                }
            } receiveValue: { [unowned self] (roleDetailResponse, applicantListResponse) in
                let roleDetail = roleDetailResponse.data
                let applicantList = applicantListResponse.data
                
                let jsonDecoder = JSONDecoder()
                
                do {
                    let roleDetailDecoded = try jsonDecoder.decode(ApiResponse<GetAuditionRoleDetailResponse>.self, from: roleDetail)
                    if let data = roleDetailDecoded.data, roleDetailDecoded.success {
                        self.name = data.name
                        self.auditionRoleDetail = data
                    } else {
                        if let message = roleDetailDecoded.message {
                            self.errorMessage = message
                        } else {
                            self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
                        }
                        
                        self.isShowPopup = true
                    }
                } catch {
                    self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
                    self.isShowPopup = true
                }
                
                do {
                    let applicantListDecoded = try jsonDecoder.decode(ApiResponse<GetAuditionApplicantListResponse>.self, from: applicantList)
                    if let data = applicantListDecoded.data, applicantListDecoded.success {
                        self.totalCount = data.totalCount
                        self.applicantList.append(contentsOf: data.items)
                        
                        if data.items.isEmpty {
                            isLast = true
                        } else {
                            page += 1
                        }
                    } else {
                        if let message = applicantListDecoded.message {
                            self.errorMessage = message
                        } else {
                            self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
                        }
                        
                        self.isShowPopup = true
                        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                            self.onFailure()
                        }
                    }
                } catch {
                    self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
                    self.isShowPopup = true
                    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                        self.onFailure()
                    }
                }
                
                self.isLoading = false
            }
            .store(in: &subscription)
    }
    
    func getAuditionApplicantList() {
        if !isLoading && !isLast {
            isLoading = true
            
            repository.getAuditionApplicantList(auditionRoleId: auditionRoleId, sortType: sortType, page: page, size: pageSize)
                .sink { result in
                    switch result {
                    case .finished:
                        DEBUG_LOG("finish")
                    case .failure(let error):
                        ERROR_LOG(error.localizedDescription)
                    }
                } receiveValue: { [unowned self] response in
                    let responseData = response.data
                    self.isLoading = false
                    
                    do {
                        let jsonDecoder = JSONDecoder()
                        let decoded = try jsonDecoder.decode(ApiResponse<GetAuditionApplicantListResponse>.self, from: responseData)
                        
                        if let data = decoded.data, decoded.success {
                            self.totalCount = data.totalCount
                            self.applicantList.append(contentsOf: data.items)
                            
                            if data.items.isEmpty {
                                isLast = true
                            } else {
                                page += 1
                            }
                        } else {
                            if let message = decoded.message {
                                self.errorMessage = message
                            } else {
                                self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
                            }
                            
                            self.isShowPopup = true
                        }
                    } catch {
                        self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
                        self.isShowPopup = true
                    }
                }
                .store(in: &subscription)
        }
    }
    
    func applyAudition(onSuccess: @escaping () -> Void) {
        if phoneNumber.count != 11 {
            errorMessage = "잘못된 연락처 입니다.\n다시 입력해 주세요."
            isShowPopup = true
            return
        }
        
        guard let soundData = soundData else {
            errorMessage = "잘못된 녹음 파일 입니다.\n다시 선택해 주세요."
            isShowPopup = true
            return
        }
        
        isLoading = true
        
        let request = ApplyAuditionRoleRequest(roleId: auditionRoleId, phoneNumber: phoneNumber)
        var multipartData = [MultipartFormData]()
        
        let encoder = JSONEncoder()
        encoder.outputFormatting = .withoutEscapingSlashes
        let jsonData = try? encoder.encode(request)
        
        if let jsonData = jsonData {
            multipartData.append(MultipartFormData(provider: .data(jsonData), name: "request"))
            multipartData.append(
                MultipartFormData(
                    provider: .data(soundData),
                    name: "contentFile",
                    fileName: fileName,
                    mimeType: "audio/*"
                )
            )
            
            repository.applyAudition(parameters: multipartData)
                .sink { result in
                    switch result {
                    case .finished:
                        DEBUG_LOG("finish")
                    case .failure(let error):
                        ERROR_LOG(error.localizedDescription)
                    }
                } receiveValue: { response in
                    self.isLoading = false
                    let responseData = response.data
                    
                    do {
                        let jsonDecoder = JSONDecoder()
                        let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
                        
                        if decoded.success {
                            self.errorMessage = "오디션 지원이 완료되었습니다."
                            self.isShowPopup = true
                            self.deleteAllRecordingFilesWithNamePrefix("voiceon_now_voice")
                            self.applicantList = []
                            self.totalCount = 0
                            
                            self.page = 1
                            self.isLast = false
                            self.getAuditionRoleDetail()
                            
                            onSuccess()
                        } else {
                            if let message = decoded.message {
                                self.errorMessage = message
                            } else {
                                self.errorMessage = "오디션 지원을 완료하지 못했습니다.\n다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
                            }
                            
                            self.isShowPopup = true
                        }
                    } catch {
                        self.errorMessage = "오디션 지원을 완료하지 못했습니다.\n다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
                        self.isShowPopup = true
                    }
                }
                .store(in: &subscription)
        } else {
            self.errorMessage = "오디션 지원을 완료하지 못했습니다.\n다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
            self.isShowPopup = true
            self.isLoading = false
        }
    }
    
    func deleteAllRecordingFilesWithNamePrefix(_ prefix: String) {
        let fileManager = FileManager.default
        let documentsURL = getDocumentsDirectory()

        do {
            let fileURLs = try fileManager.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil, options: [])
            for fileURL in fileURLs {
                if fileURL.lastPathComponent.hasPrefix(prefix) {
                    try fileManager.removeItem(at: fileURL)
                    DEBUG_LOG("녹음 파일 삭제 성공: \(fileURL)")
                }
            }
        } catch {
            DEBUG_LOG("녹음 파일 삭제 실패: \(error.localizedDescription)")
        }
    }
    
    private func getDocumentsDirectory() -> URL {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    }
}
