import Foundation

/// Typed error decoded from the contract's two error body shapes ({detail: String} OR
/// {detail: {error_code, message}}) and keyed by HTTP status.
///
/// Boundary note: an in-body synthesis failure (AskResponse.synthesis_status == "backend_unavailable")
/// is an HTTP success and is NOT a DSError — only a true HTTP 503 maps to .serviceUnavailable.
public enum DSError: Error, Sendable {
    case unauthorized(message: String?)
    case notFound(message: String?)
    case validation(message: String?, errorCode: String?)
    case serviceUnavailable(message: String?)
    case server(status: Int, message: String?, errorCode: String?)
    case transport(underlying: String)
    case decoding(String)

    public var isAuthExpired: Bool {
        if case .unauthorized = self { return true }
        return false
    }

    public static func from(status: Int, data: Data) -> DSError {
        let body = DSErrorBody.parse(data)
        switch status {
        case 401: return .unauthorized(message: body?.message)
        case 404: return .notFound(message: body?.message)
        case 422: return .validation(message: body?.message, errorCode: body?.errorCode)
        case 503: return .serviceUnavailable(message: body?.message)
        default: return .server(status: status, message: body?.message, errorCode: body?.errorCode)
        }
    }
}

struct DSErrorBody {
    let message: String?
    let errorCode: String?

    static func parse(_ data: Data) -> DSErrorBody? {
        guard let obj = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return nil }
        if let s = obj["detail"] as? String {
            return DSErrorBody(message: s, errorCode: nil)
        }
        if let d = obj["detail"] as? [String: Any] {
            return DSErrorBody(message: d["message"] as? String, errorCode: d["error_code"] as? String)
        }
        return nil
    }
}

extension DSError: LocalizedError {
    public var errorDescription: String? {
        switch self {
        case .unauthorized(let m): return m ?? "인증이 만료되었습니다. 다시 로그인하세요."
        case .notFound(let m): return m ?? "찾을 수 없습니다."
        case .validation(let m, _): return m ?? "요청이 올바르지 않습니다."
        case .serviceUnavailable(let m): return m ?? "서비스를 일시적으로 사용할 수 없습니다."
        case .server(let s, let m, _): return m ?? "서버 오류 (\(s))"
        case .transport(let u): return "네트워크 오류: \(u)"
        case .decoding(let d): return "응답 해석 실패: \(d)"
        }
    }
}
