//
//  SignUpViewModel.swift
//  SodaLive
//
//  Created by klaus on 2023/08/09.
//

import UIKit
import Combine

import Moya

final class SignUpViewModel: ObservableObject {
    private let repository = UserRepository()
    private var subscription = Set<AnyCancellable>()
    
    @Published var errorMessage = ""
    @Published var isShowPopup = false
    @Published var isLoading = false
    
    @Published var email = ""
    @Published var nickname = ""
    @Published var gender: Gender = .NONE
    
    @Published var password = ""
    @Published var passwordConfirm = ""
    
    @Published var profileImage: UIImage? = nil
    
    @Published var isAgreeTerms = false
    @Published var isAgreePrivacyPolicy = false
    
    enum Step {
        case step1, step2
    }
    
    @Published private(set) var step = Step.step1
    
    func prevStep() {
        if step == .step1 {
            AppState.shared.back()
        } else {
            step = .step1
        }
    }
    
    func nextStep() {
        if validateStep1() {
            step = .step2
        }
    }
    
    func signUp() {
        if validateStep2() {
            isLoading = true
            
            let request = SignUpRequest(
                email: email,
                password: password,
                nickname: nickname,
                gender: gender,
                isAgreeTermsOfService: true,
                isAgreePrivacyPolicy: true
            )
            
            var multipartData = [MultipartFormData]()
            
            let encoder = JSONEncoder()
            encoder.outputFormatting = .withoutEscapingSlashes
            let jsonData = try? encoder.encode(request)
            
            if let jsonData = jsonData {
                if let profileImage = profileImage, let imageData = profileImage.jpegData(compressionQuality: 0.8) {
                    multipartData.append(
                        MultipartFormData(
                            provider: .data(imageData),
                            name: "profileImage",
                            fileName: "\(UUID().uuidString)_\(Date().timeIntervalSince1970 * 1000).jpg",
                            mimeType: "image/*")
                    )
                }
                
                multipartData.append(MultipartFormData(provider: .data(jsonData), name: "request"))
                
                repository.signUp(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(ApiResponse<LoginResponse>.self, from: responseData)
                            
                            if let data = decoded.data, decoded.success {
                                UserDefaults.set(data.profileImage, forKey: .profileImage)
                                UserDefaults.set(data.nickname, forKey: .nickname)
                                UserDefaults.set(data.userId, forKey: .userId)
                                UserDefaults.set(data.email, forKey: .email)
                                UserDefaults.set(data.token, forKey: .token)
                                AppState.shared.back()
                            } 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)
            } else {
                self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
                self.isShowPopup = true
                self.isLoading = false
            }
        }
    }
    
    private func validateStep1() -> Bool {
        if email.trimmingCharacters(in: .whitespaces).isEmpty || !validateEmail() {
            errorMessage = "올바른 이메일을 입력하세요"
            isShowPopup = true
            return false
        }
        
        if password.trimmingCharacters(in: .whitespaces).isEmpty {
            errorMessage = "비밀번호를 입력하세요"
            isShowPopup = true
            return false
        }
        
        if !validatePassword() {
            errorMessage = "영문, 숫자 포함 8자 이상의 비밀번호를 입력해 주세요."
            isShowPopup = true
            return false
        }
        
        if password != passwordConfirm {
            errorMessage = "비밀번호가 일치하지 않습니다."
            isShowPopup = true
            return false
        }
        
        if !isAgreeTerms || !isAgreePrivacyPolicy {
            errorMessage = "약관에 동의하셔야 회원가입이 가능합니다."
            isShowPopup = true
            return false
        }
        
        return true
    }
    
    func validateStep2() -> Bool {
        if nickname.trimmingCharacters(in: .whitespaces).isEmpty || nickname.trimmingCharacters(in: .whitespaces).count < 2 {
            errorMessage = "닉네임은 2자 이상 입력해 주세요."
            isShowPopup = true
            return false
        }
        
        return true
    }
    
    private func validateEmail() -> Bool {
        let emailRegEx = "^.+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2}[A-Za-z]*$"
        
        let predicate = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        return predicate.evaluate(with: email)
    }
    
    private func validatePassword() -> Bool {
        let passwordRegEx = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d$@!%*#?&]{8,}$"
        
        let predicate = NSPredicate(format:"SELF MATCHES %@", passwordRegEx)
        return predicate.evaluate(with: password)
    }
}
