using ScadaLink.Commons.Entities.Templates;

namespace ScadaLink.TemplateEngine;

/// <summary>
/// Enforces locking rules for template member overrides.
///
/// Locking rules:
/// - Locked members cannot be overridden downstream (child templates or compositions).
/// - Any level can lock an unlocked member (intermediate locking).
/// - Once locked, a member stays locked — it cannot be unlocked downstream.
///
/// Override granularity:
/// - Attributes: Value and Description overridable; DataType and DataSourceReference fixed.
/// - Alarms: Priority, TriggerConfiguration, Description, OnTriggerScript overridable; Name and TriggerType fixed.
/// - Scripts: Code, TriggerConfiguration, MinTimeBetweenRuns, params/return overridable; Name fixed.
/// - Lock flag applies to the entire member (attribute/alarm/script).
/// </summary>
public static class LockEnforcer
{
    /// <summary>
    /// Validates that an attribute override does not violate lock or granularity rules.
    /// </summary>
    public static string? ValidateAttributeOverride(
        TemplateAttribute original,
        TemplateAttribute proposed)
    {
        if (original.IsLocked)
        {
            return $"Attribute '{original.Name}' is locked and cannot be overridden.";
        }

        // DataType is fixed — cannot change
        if (proposed.DataType != original.DataType)
        {
            return $"Attribute '{original.Name}': DataType cannot be overridden (fixed).";
        }

        // DataSourceReference is fixed — cannot change
        if (proposed.DataSourceReference != original.DataSourceReference)
        {
            return $"Attribute '{original.Name}': DataSourceReference cannot be overridden (fixed).";
        }

        return null;
    }

    /// <summary>
    /// Validates that an alarm override does not violate lock or granularity rules.
    /// </summary>
    public static string? ValidateAlarmOverride(
        TemplateAlarm original,
        TemplateAlarm proposed)
    {
        if (original.IsLocked)
        {
            return $"Alarm '{original.Name}' is locked and cannot be overridden.";
        }

        // Name is fixed
        if (proposed.Name != original.Name)
        {
            return $"Alarm '{original.Name}': Name cannot be overridden (fixed).";
        }

        // TriggerType is fixed
        if (proposed.TriggerType != original.TriggerType)
        {
            return $"Alarm '{original.Name}': TriggerType cannot be overridden (fixed).";
        }

        return null;
    }

    /// <summary>
    /// Validates that a script override does not violate lock or granularity rules.
    /// </summary>
    public static string? ValidateScriptOverride(
        TemplateScript original,
        TemplateScript proposed)
    {
        if (original.IsLocked)
        {
            return $"Script '{original.Name}' is locked and cannot be overridden.";
        }

        // Name is fixed
        if (proposed.Name != original.Name)
        {
            return $"Script '{original.Name}': Name cannot be overridden (fixed).";
        }

        return null;
    }

    /// <summary>
    /// Validates that a lock flag change is legal.
    /// Locking is allowed on unlocked members. Unlocking is never allowed.
    /// </summary>
    public static string? ValidateLockChange(bool originalIsLocked, bool proposedIsLocked, string memberName)
    {
        if (originalIsLocked && !proposedIsLocked)
        {
            return $"Member '{memberName}' is locked and cannot be unlocked.";
        }

        return null;
    }
}
