//
//  APIService.swift - 各模块 API 调用封装
//

import Foundation

// MARK: - Waitlist

@MainActor
class WaitlistService {
    static let shared = WaitlistService()
    private let client = APIClient.shared

    func join(email: String, nickname: String?, devices: [String]?,
              interests: [String]?, painpoint: String?, willingBeta: Bool = true) async throws -> WaitlistEntry {
        let body = WaitlistCreateRequest(email: email, nickname: nickname, devices: devices,
                                          interests: interests, painpoint: painpoint, willingBeta: willingBeta)
        return try await client.request("/waitlist", method: "POST", body: body)
    }

    func stats() async throws -> WaitlistStats {
        return try await client.request("/waitlist/stats")
    }
}

// MARK: - Auth

@MainActor
class AuthService {
    static let shared = AuthService()
    private let client = APIClient.shared

    func appleLogin(identityToken: String, authorizationCode: String? = nil, givenName: String?, familyName: String?, nonce: String? = nil) async throws -> AuthResponse {
        let body = AppleAuthRequest(
            identityToken: identityToken,
            authorizationCode: authorizationCode,
            fullName: givenName != nil
                ? AppleAuthRequest.AppleFullName(givenName: givenName, familyName: familyName)
                : nil,
            nonce: nonce
        )
        return try await client.request("/auth/apple", method: "POST", body: body)
    }
}

// MARK: - User

@MainActor
class UserService {
    static let shared = UserService()
    private let client = APIClient.shared

    func myProfile() async throws -> UserProfileResponse {
        return try await client.request("/users/me")
    }

    func updateProfile(_ dto: UpdateProfileRequest) async throws -> UserProfileResponse {
        return try await client.request("/users/me", method: "PATCH", body: dto)
    }

    func updatePreferences(_ dto: UpdatePreferencesRequest) async throws -> UserPreferences {
        return try await client.request("/users/me/preferences", method: "PATCH", body: dto)
    }

    func getProfileDetail() async throws -> UserProfileData {
        return try await client.request("/users/me/profile")
    }

    func updateProfileDetail(_ dto: UpdateProfileDataRequest) async throws -> UserProfileData {
        return try await client.request("/users/me/profile", method: "PATCH", body: dto)
    }

    func requestAccountDeletion() async throws -> GenericSuccessResponse {
        return try await client.request("/users/me/deletion-request", method: "POST")
    }

    func cancelDeletion() async throws -> GenericSuccessResponse {
        return try await client.request("/users/me/deletion-request", method: "DELETE")
    }

    func listDevices() async throws -> [UserDevice] {
        return try await client.request("/users/me/devices")
    }

    func removeDevice(id: String) async throws -> GenericSuccessResponse {
        return try await client.request("/users/me/devices/\(id)", method: "DELETE")
    }

    func fetchAssets() async throws -> AssetsResponse {
        return try await client.request("/users/me/assets-summary")
    }

    func fetchStorage() async throws -> StorageResponse {
        return try await client.request("/users/me/storage")
    }
}

struct UserDevice: Codable, Identifiable {
    let id: String
    let deviceName: String?
    let deviceType: String?
    let lastSeenAt: String?
}

// MARK: - Knowledge Base

@MainActor
class KnowledgeBaseService {
    static let shared = KnowledgeBaseService()
    private let client = APIClient.shared

    func list(page: Int = 1, limit: Int = 20) async throws -> [KnowledgeBase] {
        return try await client.request("/knowledge-bases", queryItems: [
            URLQueryItem(name: "page", value: String(page)),
            URLQueryItem(name: "limit", value: String(limit)),
        ])
    }

    func create(title: String, description: String?, coverKey: String? = nil) async throws -> KnowledgeBase {
        let body = CreateKnowledgeBaseRequest(title: title, description: description, coverKey: coverKey)
        return try await client.request("/knowledge-bases", method: "POST", body: body)
    }

    func detail(id: String) async throws -> KnowledgeBase {
        return try await client.request("/knowledge-bases/\(id)")
    }

    func update(id: String, title: String?, description: String?) async throws -> KnowledgeBase {
        let body = CreateKnowledgeBaseRequest(title: title ?? "", description: description)
        return try await client.request("/knowledge-bases/\(id)", method: "PATCH", body: body)
    }

    func listSubscribed(page: Int = 1, limit: Int = 20) async throws -> [KnowledgeBase] {
        return try await client.request("/knowledge-bases/subscribed", queryItems: [
            URLQueryItem(name: "page", value: String(page)),
            URLQueryItem(name: "limit", value: String(limit)),
        ])
    }

    func delete(id: String) async throws -> GenericSuccessResponse {
        return try await client.request("/knowledge-bases/\(id)", method: "DELETE")
    }
}

// MARK: - Knowledge Items

@MainActor
class KnowledgeItemService {
    static let shared = KnowledgeItemService()
    private let client = APIClient.shared

    func list(knowledgeBaseId: String) async throws -> [KnowledgeItem] {
        return try await client.request("/knowledge-items", queryItems: [
            URLQueryItem(name: "knowledgeBaseId", value: knowledgeBaseId),
        ])
    }

    func detail(id: String) async throws -> KnowledgeItem {
        return try await client.request("/knowledge-items/\(id)")
    }

    func create(knowledgeBaseId: String, title: String, content: String?, itemType: String? = nil) async throws -> KnowledgeItem {
        let body = CreateKnowledgeItemRequest(
            knowledgeBaseId: knowledgeBaseId,
            title: title,
            content: content,
            itemType: itemType
        )
        return try await client.request("/knowledge-items", method: "POST", body: body)
    }

    func update(id: String, title: String?, content: String?, summary: String?) async throws -> KnowledgeItem {
        let body = UpdateKnowledgeItemRequest(title: title, content: content, summary: summary)
        return try await client.request("/knowledge-items/\(id)", method: "PATCH", body: body)
    }

    func delete(id: String) async throws {
        let _: GenericSuccessResponse = try await client.request("/knowledge-items/\(id)", method: "DELETE")
    }

    func batchDelete(ids: [String]) async throws -> BatchDeleteResponse {
        return try await client.request("/knowledge-items/batch-delete", method: "POST", body: ["ids": ids])
    }
}

// MARK: - Active Recall

@MainActor
class ActiveRecallService {
    static let shared = ActiveRecallService()
    private let client = APIClient.shared

    func questions(page: Int = 1, limit: Int = 20) async throws -> [ActiveRecallQuestion] {
        return try await client.request("/active-recalls", queryItems: [
            URLQueryItem(name: "page", value: String(page)),
            URLQueryItem(name: "limit", value: String(limit)),
        ])
    }

    func submit(questionId: String, answerText: String) async throws -> ActiveRecallAnswer {
        let body = SubmitAnswerRequest(answerText: answerText)
        return try await client.request("/active-recalls/\(questionId)/submit", method: "POST", body: body)
    }
}

// MARK: - AI Analysis

@MainActor
class AIAnalysisService {
    static let shared = AIAnalysisService()
    private let client = APIClient.shared

    func analyze(questionText: String, knowledgeItemContent: String, userAnswer: String) async throws -> AIAnalysisResult {
        let body = AIAnalysisRequest(
            questionText: questionText,
            knowledgeItemContent: knowledgeItemContent,
            userAnswer: userAnswer,
            text: nil,
            type: nil
        )
        return try await client.request("/ai-analysis", method: "POST", body: body)
    }
}

// MARK: - Learning Sessions

@MainActor
class LearningSessionService {
    static let shared = LearningSessionService()
    private let client = APIClient.shared

    func list(page: Int = 1, limit: Int = 20) async throws -> [LearningSession] {
        return try await client.request("/learning-sessions", queryItems: [
            URLQueryItem(name: "page", value: String(page)),
            URLQueryItem(name: "limit", value: String(limit)),
        ])
    }

    func start(knowledgeBaseId: String? = nil, knowledgeItemId: String? = nil, mode: String? = nil) async throws -> LearningSession {
        let body = CreateLearningSessionRequest(
            knowledgeBaseId: knowledgeBaseId,
            knowledgeItemId: knowledgeItemId,
            mode: mode
        )
        return try await client.request("/learning-sessions", method: "POST", body: body)
    }

    func end(id: String) async throws -> LearningSession {
        return try await client.request("/learning-sessions/\(id)/end", method: "POST")
    }

}

// MARK: - Review

@MainActor
class ReviewService {
    static let shared = ReviewService()
    private let client = APIClient.shared

    func dueCards() async throws -> [ReviewCard] {
        return try await client.request("/reviews/due")
    }

    func submit(id: String, rating: String, responseText: String? = nil) async throws -> GenericSuccessResponse {
        let body = SubmitReviewRequest(rating: rating, responseText: responseText)
        return try await client.request("/reviews/\(id)/submit", method: "POST", body: body)
    }

    func generateCards() async throws -> GenericSuccessResponse {
        return try await client.request("/reviews/generate-cards", method: "POST")
    }
}

// MARK: - Focus Items

@MainActor
class FocusItemService {
    static let shared = FocusItemService()
    private let client = APIClient.shared

    func list(page: Int = 1, limit: Int = 20) async throws -> [FocusItem] {
        return try await client.request("/focus-items", queryItems: [
            URLQueryItem(name: "page", value: String(page)),
            URLQueryItem(name: "limit", value: String(limit)),
        ])
    }

    func update(id: String, masteryScore: Int? = nil, title: String? = nil) async throws -> FocusItem {
        let body = FocusItemUpdateRequest(masteryScore: masteryScore, title: title)
        return try await client.request("/focus-items/\(id)", method: "PATCH", body: body)
    }

    func complete(id: String) async throws -> GenericSuccessResponse {
        return try await client.request("/focus-items/\(id)/complete", method: "POST")
    }
}

// MARK: - Activity & Stats

@MainActor
class ActivityService {
    static let shared = ActivityService()
    private let client = APIClient.shared

    func summary() async throws -> ActivitySummary {
        return try await client.request("/activity/summary")
    }

    func heatmap() async throws -> [String: Int] {
        return try await client.request("/activity/heatmap")
    }

    func trend(days: Int = 7) async throws -> [ActivityTrend] {
        return try await client.request("/activity/trend?days=\(days)")
    }

    func streak() async throws -> ActivityStreak {
        return try await client.request("/activity/streak")
    }

    func recommendations() async throws -> [ActivityRecommendation] {
        return try await client.request("/activity/recommendations")
    }
}

// MARK: - Feedback

@MainActor
class FeedbackService {
    static let shared = FeedbackService()
    private let client = APIClient.shared

    func submit(category: String = "general", content: String, email: String? = nil) async throws -> FeedbackData {
        let body = FeedbackCreateRequest(category: category, content: content, email: email)
        return try await client.request("/feedback", method: "POST", body: body)
    }
}

// MARK: - RAG Chat

@MainActor
class RagChatService {
    static let shared = RagChatService()
    private let client = APIClient.shared

    func createSession(knowledgeBaseId: String, title: String? = nil) async throws -> ChatSession {
        let body = CreateSessionRequest(knowledgeBaseId: knowledgeBaseId, title: title)
        return try await client.request("/rag-chat/sessions", method: "POST", body: body)
    }

    func listSessions() async throws -> [ChatSession] {
        return try await client.request("/rag-chat/sessions")
    }

    func getMessages(sessionId: String) async throws -> [ChatMessage] {
        return try await client.request("/rag-chat/sessions/\(sessionId)/messages")
    }

    func sendMessage(sessionId: String, content: String) async throws -> SendMessageResponse {
        let body = SendMessageRequest(content: content)
        return try await client.request("/rag-chat/sessions/\(sessionId)/messages", method: "POST", body: body)
    }

    func deleteSession(id: String) async throws {
        let _: GenericSuccessResponse = try await client.request("/rag-chat/sessions/\(id)", method: "DELETE")
    }
}

// MARK: - Document Import

@MainActor
class DocumentImportService {
    static let shared = DocumentImportService()
    private let client = APIClient.shared

    func create(knowledgeBaseId: String, fileName: String? = nil, sourceType: String? = "file", rawText: String? = nil) async throws -> ImportStatusResponse {
        let body = CreateImportRequest(knowledgeBaseId: knowledgeBaseId, fileName: fileName, sourceType: sourceType, rawText: rawText)
        return try await client.request("/imports", method: "POST", body: body)
    }

    func getStatus(id: String) async throws -> ImportStatusResponse {
        return try await client.request("/imports/\(id)/status")
    }
}

// MARK: - Import Candidate

@MainActor
class ImportCandidateService {
    static let shared = ImportCandidateService()
    private let client = APIClient.shared

    func listBySource(sourceId: String) async throws -> [ImportCandidate] {
        return try await client.request("/knowledge-sources/\(sourceId)/import-candidates")
    }

    func detail(id: String) async throws -> ImportCandidate {
        return try await client.request("/import-candidates/\(id)")
    }

    func update(id: String, title: String?, content: String?) async throws -> ImportCandidate {
        var body: [String: String] = [:]
        if let t = title { body["title"] = t }
        if let c = content { body["content"] = c }
        return try await client.request("/import-candidates/\(id)", method: "PATCH", body: body)
    }

    func accept(id: String) async throws -> GenericSuccessResponse {
        return try await client.request("/import-candidates/\(id)/accept", method: "POST")
    }

    func reject(id: String) async throws -> GenericSuccessResponse {
        return try await client.request("/import-candidates/\(id)/reject", method: "POST")
    }

    func batchAccept(sourceId: String) async throws -> GenericSuccessResponse {
        let body = BatchAcceptRequest(sourceId: sourceId)
        return try await client.request("/import-candidates/batch-accept", method: "POST", body: body)
    }
}

// MARK: - Knowledge Source

@MainActor
class KnowledgeSourceService {
    static let shared = KnowledgeSourceService()
    private let client = APIClient.shared

    func list(kbId: String) async throws -> [KnowledgeSource] {
        return try await client.request("/knowledge-bases/\(kbId)/sources")
    }

    func detail(kbId: String, id: String) async throws -> KnowledgeSource {
        return try await client.request("/knowledge-bases/\(kbId)/sources/\(id)")
    }

    func add(kbId: String, fileId: String? = nil, type: String? = nil, title: String? = nil) async throws -> KnowledgeSource {
        let body = AddSourceRequest(fileId: fileId, type: type, title: title)
        return try await client.request("/knowledge-bases/\(kbId)/sources", method: "POST", body: body)
    }

    func delete(kbId: String, id: String) async throws -> GenericSuccessResponse {
        return try await client.request("/knowledge-bases/\(kbId)/sources/\(id)", method: "DELETE")
    }
}

// MARK: - Quiz

@MainActor
class QuizService {
    static let shared = QuizService()
    private let client = APIClient.shared

    func generate(knowledgeBaseId: String, questionCount: Int = 5) async throws -> Quiz {
        let body = QuizGenerateRequest(knowledgeBaseId: knowledgeBaseId, questionCount: questionCount)
        return try await client.request("/quizzes", method: "POST", body: body)
    }

    func list(knowledgeBaseId: String? = nil) async throws -> [Quiz] {
        var items: [URLQueryItem]? = nil
        if let kb = knowledgeBaseId { items = [URLQueryItem(name: "knowledgeBaseId", value: kb)] }
        return try await client.request("/quizzes", queryItems: items)
    }

    func detail(id: String) async throws -> Quiz { return try await client.request("/quizzes/\(id)") }
    func start(quizId: String) async throws -> QuizAttempt { return try await client.request("/quizzes/\(quizId)/start", method: "POST") }
    func submit(quizId: String, attemptId: String, answers: [QuizAnswerItem]) async throws -> QuizSubmitResponse {
        let body = QuizSubmitRequest(attemptId: attemptId, answers: answers)
        return try await client.request("/quizzes/\(quizId)/submit", method: "POST", body: body)
    }
    func results(quizId: String, attemptId: String) async throws -> QuizAttempt { return try await client.request("/quizzes/\(quizId)/results?attemptId=\(attemptId)") }
    func history() async throws -> [QuizAttempt] { return try await client.request("/quizzes/history/list") }
}

// MARK: - Notifications

@MainActor
class NotificationService {
    static let shared = NotificationService()
    private let client = APIClient.shared

    func list(page: Int = 1, limit: Int = 20) async throws -> [NotificationItem] {
        return try await client.request("/notifications", queryItems: [
            URLQueryItem(name: "page", value: String(page)),
            URLQueryItem(name: "limit", value: String(limit)),
        ])
    }

    func markRead(id: String) async throws -> NotificationItem {
        return try await client.request("/notifications/\(id)/read", method: "PATCH")
    }

    func markAllRead() async throws -> GenericSuccessResponse {
        return try await client.request("/notifications/read-all", method: "POST")
    }

    func getPreferences() async throws -> NotificationPreferences {
        return try await client.request("/notifications/preferences")
    }

    func updatePreferences(_ dto: NotificationPreferences) async throws -> NotificationPreferences {
        return try await client.request("/notifications/preferences", method: "PATCH", body: dto)
    }

    func registerPushToken(_ token: String) async throws -> GenericSuccessResponse {
        return try await client.request("/notifications/push-token", method: "POST", body: ["token": token])
    }

    func removePushToken(_ token: String) async throws -> GenericSuccessResponse {
        return try await client.request("/notifications/push-tokens/\(token)", method: "DELETE")
    }
}

struct NotificationPreferences: Codable {
    var reviewReminder: Bool?
    var newFeatures: Bool?
    var systemNotice: Bool?
}

struct FocusItemUpdateRequest: Codable {
    let masteryScore: Int?
    let title: String?
}

struct FocusItemCompleteRequest: Codable {
    let id: String
}
