import Foundation
import Observation

// MARK: - ServerProfile

struct ServerProfile: Codable, Identifiable, Hashable {
    let id: UUID
    var name: String
    var serverURL: String
}

// MARK: - ServerProfileStore

@Observable
final class ServerProfileStore {
    static let shared = ServerProfileStore()

    private(set) var profiles: [ServerProfile] = []
    private(set) var activeProfileId: UUID?

    var activeProfile: ServerProfile? {
        profiles.first { $0.id == activeProfileId }
    }

    private let profilesKey = "serverProfiles"
    private let activeIdKey = "activeProfileId"

    private init() {
        load()
        migrate()
    }

    // MARK: - Add

    /// Adds a new profile and persists its credentials synchronously.
    func addProfile(_ profile: ServerProfile, tokenId: String, tokenSecret: String) {
        KeychainService.saveCredentialsSync(tokenId: tokenId, tokenSecret: tokenSecret, profileId: profile.id)
        profiles.append(profile)
        save()
        activate(profile)
    }

    // MARK: - Activate

    func activate(_ profile: ServerProfile) {
        guard let creds = KeychainService.loadCredentialsSync(profileId: profile.id) else { return }
        activeProfileId = profile.id
        UserDefaults.standard.set(profile.id.uuidString, forKey: activeIdKey)
        // Keep legacy "serverURL" key in sync for BookStackAPI
        UserDefaults.standard.set(profile.serverURL, forKey: "serverURL")
        Task {
            await BookStackAPI.shared.configure(
                serverURL: profile.serverURL,
                tokenId: creds.tokenId,
                tokenSecret: creds.tokenSecret
            )
        }
    }

    // MARK: - Remove

    func remove(_ profile: ServerProfile) {
        profiles.removeAll { $0.id == profile.id }
        KeychainService.deleteCredentialsSync(profileId: profile.id)
        save()
        if activeProfileId == profile.id {
            activeProfileId = nil
            UserDefaults.standard.removeObject(forKey: activeIdKey)
            UserDefaults.standard.removeObject(forKey: "serverURL")
        }
    }

    // MARK: - Update

    /// Updates the name/URL of an existing profile. Optionally rotates credentials.
    func updateProfile(_ profile: ServerProfile, newName: String, newURL: String,
                       newTokenId: String? = nil, newTokenSecret: String? = nil) {
        guard let idx = profiles.firstIndex(where: { $0.id == profile.id }) else { return }
        profiles[idx].name = newName
        profiles[idx].serverURL = newURL
        if let id = newTokenId, let secret = newTokenSecret {
            KeychainService.saveCredentialsSync(tokenId: id, tokenSecret: secret, profileId: profile.id)
        }
        save()
        // If this is the active profile, re-configure the API client
        if activeProfileId == profile.id {
            UserDefaults.standard.set(newURL, forKey: "serverURL")
            let creds = (newTokenId != nil && newTokenSecret != nil)
                ? (tokenId: newTokenId!, tokenSecret: newTokenSecret!)
                : KeychainService.loadCredentialsSync(profileId: profile.id) ?? (tokenId: "", tokenSecret: "")
            Task {
                await BookStackAPI.shared.configure(
                    serverURL: newURL,
                    tokenId: creds.tokenId,
                    tokenSecret: creds.tokenSecret
                )
            }
        }
    }

    // MARK: - Persistence

    private func save() {
        guard let data = try? JSONEncoder().encode(profiles) else { return }
        UserDefaults.standard.set(data, forKey: profilesKey)
    }

    private func load() {
        if let data = UserDefaults.standard.data(forKey: profilesKey),
           let decoded = try? JSONDecoder().decode([ServerProfile].self, from: data) {
            profiles = decoded
        }
        if let idString = UserDefaults.standard.string(forKey: activeIdKey),
           let uuid = UUID(uuidString: idString) {
            activeProfileId = uuid
        }
    }

    // MARK: - Migration from legacy single-server config

    private func migrate() {
        guard profiles.isEmpty,
              let url = UserDefaults.standard.string(forKey: "serverURL"),
              !url.isEmpty,
              let tokenId = KeychainService.loadSync(key: "tokenId"),
              let tokenSecret = KeychainService.loadSync(key: "tokenSecret") else { return }

        let profile = ServerProfile(id: UUID(), name: "BookStack", serverURL: url)
        KeychainService.saveCredentialsSync(tokenId: tokenId, tokenSecret: tokenSecret, profileId: profile.id)
        profiles.append(profile)
        save()
        activeProfileId = profile.id
        UserDefaults.standard.set(profile.id.uuidString, forKey: activeIdKey)
        // Leave legacy "serverURL" in place so BookStackAPI continues working after migration.
        AppLog(.info, "Migrated legacy server config to profile \(profile.id)", category: "ServerProfile")
    }
}
