import Foundation
import Observation

// MARK: - ServerProfile

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

    // Display options (per-profile)
    var appTheme: String = "system"
    var accentTheme: String = AccentTheme.ocean.rawValue
    var editorFontSize: Double = 16
    var readerFontSize: Double = 16
    var appTextColor: String? = nil          // nil = system default
    var appBackgroundColor: String? = nil    // nil = system default
}

// 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()
        // Ensure CredentialStore is populated for the active profile on every launch.
        // CredentialStore.init() bootstraps from UserDefaults/Keychain independently,
        // but activate() is the authoritative path — call it here to guarantee consistency.
        if let profile = profiles.first(where: { $0.id == activeProfileId }) {
            activate(profile)
        }
    }

    // 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)
        UserDefaults.standard.set(profile.serverURL, forKey: "serverURL")
        UserDefaults.standard.set(profile.appTheme, forKey: "appTheme")
        UserDefaults.standard.set(profile.accentTheme, forKey: "accentTheme")
        CredentialStore.shared.update(
            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 activeProfileId == profile.id {
            UserDefaults.standard.set(newURL, forKey: "serverURL")
            let tokenId = newTokenId ?? KeychainService.loadCredentialsSync(profileId: profile.id)?.tokenId ?? ""
            let tokenSecret = newTokenSecret ?? KeychainService.loadCredentialsSync(profileId: profile.id)?.tokenSecret ?? ""
            CredentialStore.shared.update(serverURL: newURL, tokenId: tokenId, tokenSecret: tokenSecret)
        }
    }

    // MARK: - Display Options

    func updateDisplayOptions(for profile: ServerProfile,
                              editorFontSize: Double,
                              readerFontSize: Double,
                              appTextColor: String?,
                              appBackgroundColor: String?,
                              appTheme: String,
                              accentTheme: String) {
        guard let idx = profiles.firstIndex(where: { $0.id == profile.id }) else { return }
        profiles[idx].editorFontSize = editorFontSize
        profiles[idx].readerFontSize = readerFontSize
        profiles[idx].appTextColor = appTextColor
        profiles[idx].appBackgroundColor = appBackgroundColor
        profiles[idx].appTheme = appTheme
        profiles[idx].accentTheme = accentTheme
        save()
        // Apply theme changes to app-wide UserDefaults immediately
        if activeProfileId == profile.id {
            UserDefaults.standard.set(appTheme, forKey: "appTheme")
            UserDefaults.standard.set(accentTheme, forKey: "accentTheme")
        }
    }

    // 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 CredentialStore continues working after migration.
        AppLog(.info, "Migrated legacy server config to profile \(profile.id)", category: "ServerProfile")
    }
}
