//! SCADA / industrial-control domain model for energy & utilities.
//!
//! Broad supervisory-control platform: sites and assets (substations, feeders,
//! gas regulators, pumps, inverters), tags/points (the addressable telemetry
//! and control points), real-time readings with a historian, an alarm lifecycle,
//! safety-interlocked control commands, outage events, and maintenance work
//! orders. The named agents (Asset Maintenance Planner, Gas Safety Incident,
//! Grid Outage Triage, Renewable Dispatch, Water Leak Response) are clients.
//!
//! SAFETY: control commands act on physical infrastructure. Every command is
//! validated against interlocks (asset state, alarms, ranges, lockout/tagout)
//! and is classed `external_write` + `requires_approval` in the manifest.

use chrono::{DateTime, NaiveDate, Utc};
use rmcp::schemars;
use serde::{Deserialize, Serialize};

// ─── sites & assets ──────────────────────────────────────────────────────────

/// Utility sector — drives default interlock rules and units.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, schemars::JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum Sector {
    Electric,
    Gas,
    Water,
    Renewable,
}

#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct Site {
    pub id: String,
    pub name: String,
    pub sector: Sector,
    pub region: String,
    pub created_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, schemars::JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum AssetState {
    /// Energized / running / flowing.
    InService,
    /// De-energized / stopped, available.
    OutOfService,
    /// Locked out for maintenance — control blocked (LOTO).
    LockedOut,
    /// Failed / tripped.
    Faulted,
}

#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct Asset {
    pub id: String,
    pub site_id: String,
    pub name: String,
    /// breaker | feeder | transformer | regulator | valve | pump | inverter | meter
    pub kind: String,
    pub state: AssetState,
    /// True while a lockout/tagout hold is active (no control allowed).
    pub lockout: bool,
    pub commissioned_on: Option<NaiveDate>,
    pub created_at: DateTime<Utc>,
}

// ─── tags / points ───────────────────────────────────────────────────────────

#[derive(Debug, Clone, Copy, Serialize, Deserialize, schemars::JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum PointType {
    /// Read-only measurement (analog input).
    Analog,
    /// Read-only status (digital input).
    Status,
    /// Writable setpoint (analog output).
    Setpoint,
    /// Writable command (digital output: open/close/start/stop).
    Control,
}

#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct Tag {
    pub id: String,
    pub asset_id: String,
    /// Human point name, e.g. "BKR_POS", "GAS_PRESSURE_PSI".
    pub name: String,
    pub point_type: PointType,
    pub unit: String,
    /// Engineering range / safe operating bounds (for analog/setpoint).
    pub min: Option<f64>,
    pub max: Option<f64>,
    /// Alarm thresholds.
    pub warn_high: Option<f64>,
    pub crit_high: Option<f64>,
    pub warn_low: Option<f64>,
    pub crit_low: Option<f64>,
    /// Latest value (numeric, or 0/1 for status/control).
    pub value: f64,
    pub quality: String, // good | stale | bad
    pub updated_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct Reading {
    pub tag_id: String,
    pub value: f64,
    pub quality: String,
    pub at: DateTime<Utc>,
}

// ─── alarms ──────────────────────────────────────────────────────────────────

#[derive(Debug, Clone, Copy, Serialize, Deserialize, schemars::JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum AlarmSeverity {
    Info,
    Warning,
    Critical,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, schemars::JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum AlarmState {
    /// Active and unacknowledged.
    Active,
    /// Active but acknowledged by an operator.
    Acknowledged,
    /// Condition cleared.
    Cleared,
}

#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct Alarm {
    pub id: String,
    pub asset_id: String,
    pub tag_id: Option<String>,
    pub severity: AlarmSeverity,
    pub state: AlarmState,
    pub message: String,
    pub value: Option<f64>,
    pub raised_at: DateTime<Utc>,
    pub acknowledged_at: Option<DateTime<Utc>>,
    pub acknowledged_by: Option<String>,
    pub cleared_at: Option<DateTime<Utc>>,
}

// ─── control commands ────────────────────────────────────────────────────────

#[derive(Debug, Clone, Copy, Serialize, Deserialize, schemars::JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum CommandStatus {
    /// Passed interlocks, applied to the point.
    Executed,
    /// Rejected by an interlock — never applied.
    Rejected,
}

#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct ControlCommand {
    pub id: String,
    pub tag_id: String,
    pub asset_id: String,
    /// Requested action: a setpoint value, or open/close/start/stop.
    pub action: String,
    pub requested_value: f64,
    pub status: CommandStatus,
    /// Interlocks that were checked.
    pub interlocks_checked: Vec<String>,
    /// Why it was rejected (empty if executed).
    pub rejection_reason: Option<String>,
    pub issued_by: String,
    pub at: DateTime<Utc>,
}

// ─── outages ─────────────────────────────────────────────────────────────────

#[derive(Debug, Clone, Copy, Serialize, Deserialize, schemars::JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum OutageStatus {
    Reported,
    Triaged,
    CrewDispatched,
    Restored,
}

#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct Outage {
    pub id: String,
    pub site_id: String,
    pub asset_id: Option<String>,
    pub cause: String,
    pub status: OutageStatus,
    /// Computed triage priority P1 (highest) .. P4.
    pub priority: String,
    pub customers_affected: u32,
    /// Safety hazard present (gas leak, downed line, flooding).
    pub safety_hazard: bool,
    pub reported_at: DateTime<Utc>,
    pub restored_at: Option<DateTime<Utc>>,
}

// ─── maintenance ─────────────────────────────────────────────────────────────

#[derive(Debug, Clone, Copy, Serialize, Deserialize, schemars::JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum WorkOrderStatus {
    Open,
    Scheduled,
    InProgress,
    Completed,
    Cancelled,
}

#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct WorkOrder {
    pub id: String,
    pub asset_id: String,
    /// preventive | corrective | inspection | emergency
    pub kind: String,
    pub priority: String,
    pub status: WorkOrderStatus,
    pub description: String,
    pub scheduled_for: Option<NaiveDate>,
    pub assigned_to: Option<String>,
    pub created_at: DateTime<Utc>,
    pub completed_at: Option<DateTime<Utc>>,
}

// ─── audit trail ───────────────────────────────────────────────────────────

#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct AuditEntry {
    pub at: DateTime<Utc>,
    pub actor: String,
    pub action: String,
    pub detail: String,
}
