// NTPPlugInController.swift
//
// Principal class for the NTP analyzer plugin. Loaded once at host launch.
// Registers the plugin with the host's CPAPlugInsController and provides
// the (very simple) preferences surface.

import AppKit
import SwiftUI
import CPAPluginSDK

@MainActor
final class NTPPlugInController: NSObject, ObservableObject,
    CPAPluginPrincipalClassProtocol,
    CPAPluginPreferencesProtocol {

    // MARK: - User-defaults keys

    private static let kUsesColor = "com_example_cpa_ntp_color_use"
    private static let kColorRaw = "com_example_cpa_ntp_color"
    private static let defaultPort = 123
    private static let protocolName = "NTP"

    // MARK: - Init

    required convenience init?(plugInsController: Any) { self.init() }
    required convenience init?(plugInManager: Any) { self.init() }

    override required convenience init() {
        self.init(controller: CPAPlugInsController.sharedManager)!
    }

    init?(controller: CPAPlugInsController) {
        super.init()
        applyDefaults()
        register(with: controller)
    }

    // MARK: - Plugin metadata (CPAPluginPrincipalClassProtocol)

    static func pluginTitle() -> String? {
        Bundle(for: NTPPlugInController.self).localized("NTP Analyzer")
    }

    static func pluginDescription() -> String? {
        Bundle(for: NTPPlugInController.self).localized("Network Time Protocol v4 Analyzer (RFC 5905)")
    }

    static func pluginVersion() -> String? {
        let bundle = Bundle(for: NTPPlugInController.self)
        let short = bundle.infoDictionary?["CFBundleShortVersionString"] as? String ?? "0"
        let build = bundle.infoDictionary?[kCFBundleVersionKey as String] as? String ?? "0"
        return "\(short) (\(build))"
    }

    static func pluginAuthor() -> String? {
        Bundle(for: NTPPlugInController.self).localized("CPA Plugin SDK example")
    }

    // MARK: - Preferences (CPAPluginPreferencesProtocol)

    func usesColor() -> Bool {
        UserDefaults.standard.bool(forKey: NTPPlugInController.kUsesColor)
    }

    func protocolColor() -> NSColor {
        if let data = UserDefaults.standard.data(forKey: NTPPlugInController.kColorRaw),
           let color = try? NSKeyedUnarchiver.unarchivedObject(ofClass: NSColor.self, from: data) {
            return color
        }
        return .systemTeal
    }

    func settingsView(_ size: Binding<CGSize>) -> AnyView {
        AnyView(NTPSettingsView(viewModel: self, tableSize: size))
    }

    func preferencesSheet() -> NSWindow? { nil }

    // MARK: - Private

    private func applyDefaults() {
        let defaults = UserDefaults.standard
        if defaults.object(forKey: NTPPlugInController.kUsesColor) == nil {
            defaults.set(false, forKey: NTPPlugInController.kUsesColor)
        }
        if defaults.object(forKey: NTPPlugInController.kColorRaw) == nil,
           let archived = try? NSKeyedArchiver.archivedData(
               withRootObject: NSColor.systemTeal.withAlphaComponent(0.7),
               requiringSecureCoding: true
           ) {
            defaults.set(archived, forKey: NTPPlugInController.kColorRaw)
        }
    }

    private func register(with controller: CPAPlugInsController) {
        let bundle = Bundle(for: type(of: self))

        let columns: [CPAPlugInColumn] = [
            CPAPlugInColumn.column(
                title: bundle.localized("NTP Size"),
                keyPath: "ntpSize",
                predicateDisplayName: bundle.localized("NTP Size contains"),
                predicateFormat: "ntpSize.description CONTAINS $value",
                attrType: NSString.self
            ),
            CPAPlugInColumn.column(
                title: bundle.localized("NTP Mode"),
                keyPath: "ntpMode",
                predicateDisplayName: bundle.localized("NTP Mode contains"),
                predicateFormat: "ntpMode CONTAINS[c] $value",
                attrType: String.self
            ),
            CPAPlugInColumn.column(
                title: bundle.localized("NTP Stratum"),
                keyPath: "ntpStratum",
                predicateDisplayName: bundle.localized("NTP Stratum contains"),
                predicateFormat: "ntpStratum.description CONTAINS $value",
                attrType: NSString.self
            ),
            CPAPlugInColumn.column(
                title: bundle.localized("NTP Reference"),
                keyPath: "ntpReference",
                predicateDisplayName: bundle.localized("NTP Reference contains"),
                predicateFormat: "ntpReference CONTAINS[c] $value",
                attrType: String.self
            ),
            CPAPlugInColumn.column(
                title: bundle.localized("NTP ProtocolInfo"),
                keyPath: "ntpProtocolInfo",
                predicateDisplayName: bundle.localized("NTP ProtocolInfo contains"),
                predicateFormat: "ntpProtocolInfo CONTAINS[c] $value",
                attrType: String.self
            )
        ]

        let attributes: [CPAPlugInAnalyzerAttribute] = [
            .attribute(class: NTPProtocolAnalyzer.self, title: bundle.localized("NTP Size"), key: "ntpSize", type: NSNumber.self),
            .attribute(class: NTPProtocolAnalyzer.self, title: bundle.localized("NTP Mode"), key: "ntpMode", type: String.self),
            .attribute(class: NTPProtocolAnalyzer.self, title: bundle.localized("NTP Stratum"), key: "ntpStratum", type: NSNumber.self),
            .attribute(class: NTPProtocolAnalyzer.self, title: bundle.localized("NTP Reference"), key: "ntpReference", type: String.self),
            .attribute(class: NTPProtocolAnalyzer.self, title: bundle.localized("NTP ProtocolInfo"), key: "ntpProtocolInfo", type: String.self)
        ]

        let plugin = CPAPlugInStructure.register(
            title: NTPPlugInController.pluginTitle() ?? "NTP",
            description: NTPPlugInController.pluginDescription() ?? "",
            version: NTPPlugInController.pluginVersion() ?? "0",
            author: NTPPlugInController.pluginAuthor() ?? "",
            principalClass: NTPPlugInController.self,
            preferences: self,
            analyzerClass: NTPProtocolAnalyzer.self,
            attributes: attributes,
            targets: [.udp(name: NTPPlugInController.protocolName, ports: [NTPPlugInController.defaultPort])],
            columns: columns
        )

        _ = controller.register(CPAPlugIn: plugin, forBundle: bundle)
        cpaLog("NTP plugin registered for UDP/\(NTPPlugInController.defaultPort)")
    }
}

// MARK: - Settings view

private struct NTPSettingsView: View {
    @ObservedObject var viewModel: NTPPlugInController
    @Binding var tableSize: CGSize

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("NTP Analyzer")
                .font(.title2)
            Text("Listening on UDP/123 (RFC 5905).")
                .foregroundStyle(.secondary)
            Text("This is the example plugin shipped with the CocoaPacketAnalyzer Plugin SDK. It demonstrates the minimum surface area: principal class, analyzer, dissector, registration. See the SDK's DocC catalog for the full guide.")
                .font(.callout)
                .foregroundStyle(.secondary)
            Spacer()
        }
        .padding(24)
        .frame(minWidth: 400, minHeight: 200)
    }
}
