import Foundation
import Observation

// MARK: - Log Entry

struct LogEntry: Identifiable, Sendable {
    enum Level: String, Sendable {
        case debug   = "DEBUG"
        case info    = "INFO"
        case warning = "WARN"
        case error   = "ERROR"

        var emoji: String {
            switch self {
            case .debug:   return "🔍"
            case .info:    return "ℹ️"
            case .warning: return "⚠️"
            case .error:   return "❌"
            }
        }
    }

    let id = UUID()
    let timestamp: Date
    let level: Level
    let category: String
    let message: String

    var formatted: String {
        let ts = LogEntry.formatter.string(from: timestamp)
        return "\(ts) \(level.emoji) [\(category)] \(message)"
    }

    private static let formatter: DateFormatter = {
        let f = DateFormatter()
        f.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
        return f
    }()
}

// MARK: - LogManager

@Observable
@MainActor
final class LogManager {
    static let shared = LogManager()

    private(set) var entries: [LogEntry] = []
    private let maxEntries = 2000

    /// Controlled via Settings toggle. Stored in UserDefaults so it survives restarts.
    var isEnabled: Bool {
        get { UserDefaults.standard.bool(forKey: "loggingEnabled") }
        set { UserDefaults.standard.set(newValue, forKey: "loggingEnabled") }
    }

    private init() {}

    // MARK: - Logging

    func log(_ level: LogEntry.Level, category: String, _ message: String) {
        guard isEnabled else { return }
        let entry = LogEntry(timestamp: Date(), level: level, category: category, message: message)
        entries.append(entry)
        if entries.count > maxEntries {
            entries.removeFirst(entries.count - maxEntries)
        }
    }

    func debug(_ message: String, category: String = "App") {
        log(.debug, category: category, message)
    }

    func info(_ message: String, category: String = "App") {
        log(.info, category: category, message)
    }

    func warning(_ message: String, category: String = "App") {
        log(.warning, category: category, message)
    }

    func error(_ message: String, category: String = "App") {
        log(.error, category: category, message)
    }

    // MARK: - Export

    func clear() {
        entries.removeAll()
    }

    /// Returns the full log as a plain-text string ready for sharing.
    func exportText() -> String {
        guard !entries.isEmpty else { return "No log entries." }
        let header = """
        BookStax Log Export
        Generated: \(Date().bookStackFormattedWithTime)
        Entries: \(entries.count)
        ────────────────────────────────────────

        """
        return header + entries.map(\.formatted).joined(separator: "\n")
    }
}

// MARK: - Global shorthand (nonisolated — dispatches to MainActor)

func AppLog(_ level: LogEntry.Level = .info, _ message: String, category: String = "App") {
    Task { @MainActor in
        LogManager.shared.log(level, category: category, message)
    }
}
