import Foundation
import Observation

enum AuthError: LocalizedError {
    case invalidURL
    case badResponse(Int)
    case noToken
    case unknown(String)

    var errorDescription: String? {
        switch self {
        case .invalidURL: return "Ungültige Server-URL."
        case .badResponse(let code): return "Server antwortete mit Status \(code)."
        case .noToken: return "Login fehlgeschlagen: kein Token erhalten."
        case .unknown(let msg): return msg
        }
    }
}

@Observable
@MainActor
final class AuthStore {
    var isLoggedIn: Bool = false
    var serverURL: String = ""
    var username: String = ""
    var token: String = ""
    var errorMessage: String?

    func restoreSession() {
        guard let creds = KeychainStore.load() else { return }
        self.serverURL = creds.serverURL
        self.username = creds.username
        self.token = creds.token
        self.isLoggedIn = true
    }

    func login(serverURL rawURL: String, username: String, password: String, remember: Bool) async {
        errorMessage = nil
        let normalized = Self.normalizeURL(rawURL)
        guard let url = URL(string: normalized + "/login") else {
            errorMessage = AuthError.invalidURL.errorDescription
            return
        }
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        let body = ["username": username, "password": password]
        request.httpBody = try? JSONEncoder().encode(body)

        do {
            let (data, response) = try await URLSession.shared.data(for: request)
            guard let http = response as? HTTPURLResponse else {
                errorMessage = "Keine HTTP-Antwort vom Server."
                return
            }
            guard (200..<300).contains(http.statusCode) else {
                errorMessage = AuthError.badResponse(http.statusCode).errorDescription
                return
            }
            let decoded = try JSONDecoder().decode(LoginResponseDTO.self, from: data)
            self.serverURL = normalized
            self.username = decoded.user.username ?? username
            self.token = decoded.user.token
            self.isLoggedIn = true

            if remember {
                try? KeychainStore.save(StoredCredentials(
                    serverURL: normalized,
                    username: self.username,
                    token: self.token
                ))
            } else {
                KeychainStore.delete()
            }
        } catch {
            errorMessage = "Login fehlgeschlagen: \(error.localizedDescription)"
        }
    }

    func logout() {
        KeychainStore.delete()
        token = ""
        isLoggedIn = false
    }

    static func normalizeURL(_ raw: String) -> String {
        var s = raw.trimmingCharacters(in: .whitespacesAndNewlines)
        while s.hasSuffix("/") { s.removeLast() }
        if !s.lowercased().hasPrefix("http://") && !s.lowercased().hasPrefix("https://") {
            s = "https://" + s
        }
        return s
    }
}
