import Foundation
import Observation

@MainActor
@Observable
final class ONUListViewModel {
    var phase: LoadPhase = .idle
    var onus: [ONUStateDoc] = []
    var search = ""

    /// When set, only ONUs in this registration state are shown (dashboard drill-down).
    let stateFilter: ONULifecycleState?

    private let connection: MCMSConnection
    /// Bumped per load so an overlapping/stale fetch can't commit over a newer one.
    private var loadGeneration = 0
    init(connection: MCMSConnection, stateFilter: ONULifecycleState? = nil) {
        self.connection = connection
        self.stateFilter = stateFilter
    }

    var filtered: [ONUStateDoc] {
        var result = onus
        if let stateFilter {
            result = result.filter { $0.lifecycle == stateFilter }
        }
        let query = search.trimmingCharacters(in: .whitespaces)
        guard !query.isEmpty else { return result }
        return result.filter { onu in
            onu.id.localizedCaseInsensitiveContains(query)
            || (onu.resolvedName?.localizedCaseInsensitiveContains(query) ?? false)
            || (onu.parentOLT?.localizedCaseInsensitiveContains(query) ?? false)
        }
    }

    func load() async {
        loadGeneration += 1
        let gen = loadGeneration
        phase = .loading
        do {
            let fetched = try await connection.onu.allStates()
            // Registration lives on OLT-STATE, operator names on ONU-CFG. Both best-effort.
            let registration = (try? await connection.olt.registrationMap()) ?? [:]
            let names = (try? await connection.onu.nameMap()) ?? [:]
            let merged: [ONUStateDoc] = fetched
                .map { onu in
                    var onu = onu
                    onu.resolvedLifecycle = registration[onu.id]
                    onu.resolvedName = names[onu.id]
                    return onu
                }
                .sorted { $0.displayName.localizedCaseInsensitiveCompare($1.displayName) == .orderedAscending }
            guard gen == loadGeneration, !Task.isCancelled else { return }
            onus = merged
            phase = .loaded
        } catch {
            guard gen == loadGeneration, !Task.isCancelled else { return }
            phase = .failed((error as? APIError)?.localizedDescription ?? error.localizedDescription)
        }
    }
}
