//******************************************************************************************************
//  Models.cs - Gbtc
//
//  Copyright © 2026, Grid Protection Alliance.  All Rights Reserved.
//
//  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
//  the NOTICE file distributed with this work for additional information regarding copyright ownership.
//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
//  file except in compliance with the License. You may obtain a copy of the License at:
//
//      http://opensource.org/licenses/MIT
//
//  Unless agreed to in writing, the subject software distributed under the License is distributed on an
//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
//  License for the specific language governing permissions and limitations.
//
//  Code Modification History:
//  ----------------------------------------------------------------------------------------------------
//  01/15/2026 - J. Ritchie Carroll
//       Generated original version of source code.
//
//******************************************************************************************************
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor.

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Gemstone.ComponentModel.DataAnnotations;
using Gemstone.Data.Model;
using Gemstone.Expressions.Model;

namespace DNP3ConfigLoader;

// NOTE: We define our own Device/Measurement models here because the Gemstone.Timeseries.Model
// versions have NodeID and ProtocolID commented out (EE version), but the .NET Framework version
// of openPDC database requires them. This code is .NET Core so it uses Gemstone instead of GSF.

/// <summary>
/// Represents a Device table record with all required fields including NodeID and ProtocolID.
/// </summary>
[PrimaryLabel(nameof(Acronym))]
public class Device
{
    public Guid NodeID { get; set; }

    [PrimaryKey(true)]
    public int ID { get; set; }

    public int? ParentID { get; set; }

    [DefaultValueExpression("Guid.NewGuid()")]
    public Guid UniqueID { get; set; }

    [Required]
    [StringLength(200)]
    public string Acronym { get; set; } = string.Empty;

    [StringLength(200)]
    public string? Name { get; set; }

    [StringLength(20)]
    public string? OriginalSource { get; set; }

    public bool IsConcentrator { get; set; }

    public int? CompanyID { get; set; }

    public int? HistorianID { get; set; }

    [DefaultValueExpression("Settings.DefaultAccessID")]
    public int AccessID { get; set; }

    public int? VendorDeviceID { get; set; }

    public int? ProtocolID { get; set; }

    public decimal? Longitude { get; set; }

    public decimal? Latitude { get; set; }

    public int? InterconnectionID { get; set; } = null;

    [DefaultValue("")]
    public string? ConnectionString { get; set; } = string.Empty;

    [StringLength(200)]
    public string? TimeZone { get; set; }

    [DefaultValueExpression("Settings.DefaultFramesPerSecond")]
    public int FramesPerSecond { get; set; } = 30;

    public long TimeAdjustmentTicks { get; set; }

    public double DataLossInterval { get; set; } = 5.0;

    public int AllowedParsingExceptions { get; set; } = 10;

    public double ParsingExceptionWindow { get; set; } = 5.0;

    public double DelayedConnectionInterval { get; set; } = 5.0;

    public bool AllowUseOfCachedConfiguration { get; set; } = true;

    public bool AutoStartDataParsingSequence { get; set; } = true;

    public bool SkipDisableRealTimeData { get; set; }

    [DefaultValueExpression("Settings.DefaultMeasurementReportingInterval")]
    public int MeasurementReportingInterval { get; set; } = 100000;

    public bool ConnectOnDemand { get; set; }

    [DefaultValue("")]
    public string? ContactList { get; set; }

    public int? MeasuredLines { get; set; }

    public int LoadOrder { get; set; }

    public bool Enabled { get; set; } = true;

    [DefaultValueExpression("DateTime.UtcNow")]
    public DateTime CreatedOn { get; set; }

    [Required]
    [StringLength(50)]
    [DefaultValueExpression("UserInfo.CurrentUserID")]
    public string CreatedBy { get; set; }

    [DefaultValueExpression("this.CreatedOn", EvaluationOrder = 1)]
    [UpdateValueExpression("DateTime.UtcNow")]
    public DateTime UpdatedOn { get; set; }

    [Required]
    [StringLength(50)]
    [DefaultValueExpression("this.CreatedBy", EvaluationOrder = 1)]
    [UpdateValueExpression("UserInfo.CurrentUserID")]
    public string UpdatedBy { get; set; }
}

/// <summary>
/// Represents a Measurement table record.
/// </summary>
[PrimaryLabel(nameof(PointTag))]
public class Measurement
{
    [PrimaryKey(true)]
    public int PointID { get; set; }

    [DefaultValueExpression("Guid.NewGuid()")]
    public Guid SignalID { get; set; }

    public int? HistorianID { get; set; }

    public int? DeviceID { get; set; }

    [Required]
    [StringLength(200)]
    public string PointTag { get; set; } = string.Empty;

    public string? AlternateTag { get; set; } = string.Empty;

    public int SignalTypeID { get; set; }

    public int? PhasorSourceIndex { get; set; }

    [Required]
    [StringLength(200)]
    public string SignalReference { get; set; } = string.Empty;

    public double Adder { get; set; }

    public double Multiplier { get; set; } = 1.0D;

    public string? Description { get; set; }

    public bool Internal { get; set; } = true;

    public bool Subscribed { get; set; }

    public bool Enabled { get; set; } = true;

    [DefaultValueExpression("DateTime.UtcNow")]
    public DateTime CreatedOn { get; set; }

    [Required]
    [StringLength(50)]
    [DefaultValueExpression("UserInfo.CurrentUserID")]
    public string CreatedBy { get; set; }

    [DefaultValueExpression("this.CreatedOn", EvaluationOrder = 1)]
    [UpdateValueExpression("DateTime.UtcNow")]
    public DateTime UpdatedOn { get; set; }

    [Required]
    [StringLength(50)]
    [DefaultValueExpression("this.CreatedBy", EvaluationOrder = 1)]
    [UpdateValueExpression("UserInfo.CurrentUserID")]
    public string UpdatedBy { get; set; }
}

/// <summary>
/// Represents a CustomActionAdapter record.
/// Note: This model may already exist in Gemstone.Timeseries.Model -
/// if so, remove this and use that one instead.
/// </summary>
public class CustomActionAdapter
{
    [PrimaryKey(true)]
    public int ID { get; set; }

    public Guid NodeID { get; set; }

    [StringLength(200)]
    public string AdapterName { get; set; } = string.Empty;

    public string AssemblyName { get; set; } = "DynamicCalculator.dll";

    public string TypeName { get; set; } = "DynamicCalculator.DynamicCalculator";

    public string? ConnectionString { get; set; }

    public int LoadOrder { get; set; }

    public bool Enabled { get; set; } = true;

    [DefaultValueExpression("DateTime.UtcNow")]
    public DateTime CreatedOn { get; set; }

    [Required]
    [StringLength(50)]
    [DefaultValueExpression("UserInfo.CurrentUserID")]
    public string CreatedBy { get; set; }

    [DefaultValueExpression("this.CreatedOn", EvaluationOrder = 1)]
    [UpdateValueExpression("DateTime.UtcNow")]
    public DateTime UpdatedOn { get; set; }

    [Required]
    [StringLength(50)]
    [DefaultValueExpression("this.CreatedBy", EvaluationOrder = 1)]
    [UpdateValueExpression("UserInfo.CurrentUserID")]
    public string UpdatedBy { get; set; }
}

/// <summary>
/// Represents a CustomFilterAdapter record.
/// Note: This model may already exist in Gemstone.Timeseries.Model -
/// if so, remove this and use that one instead.
/// </summary>
public class CustomFilterAdapter
{
    [PrimaryKey(true)]
    public int ID { get; set; }

    public Guid NodeID { get; set; }

    [StringLength(200)]
    public string AdapterName { get; set; } = string.Empty;

    public string AssemblyName { get; set; } = "DynamicCalculator.dll";

    public string TypeName { get; set; } = "DynamicCalculator.DynamicFilter";

    public string? ConnectionString { get; set; }

    public int LoadOrder { get; set; }

    public bool Enabled { get; set; } = true;

    [DefaultValueExpression("DateTime.UtcNow")]
    public DateTime CreatedOn { get; set; }

    [Required]
    [StringLength(50)]
    [DefaultValueExpression("UserInfo.CurrentUserID")]
    public string CreatedBy { get; set; }

    [DefaultValueExpression("this.CreatedOn", EvaluationOrder = 1)]
    [UpdateValueExpression("DateTime.UtcNow")]
    public DateTime UpdatedOn { get; set; }

    [Required]
    [StringLength(50)]
    [DefaultValueExpression("this.CreatedBy", EvaluationOrder = 1)]
    [UpdateValueExpression("UserInfo.CurrentUserID")]
    public string UpdatedBy { get; set; }
}

/// <summary>
/// Represents a DNP3 point mapping for XML generation.
/// </summary>
public class IndexMapping
{
    public int ID { get; set; }
    public string Source { get; set; } = string.Empty;
    public int Index { get; set; }
}

/// <summary>
/// Represents a CIM device export row.
/// </summary>
public class CIMDevice
{
    public string Name { get; set; } = string.Empty;
    public string Substation { get; set; } = string.Empty;
    public string Connection { get; set; } = string.Empty;
    public string TagMapFileName { get; set; } = string.Empty;
    public List<Dictionary<string, string?>> Rows { get; set; } = [];
}

/// <summary>
/// Represents a tag map row from CSV file.
/// </summary>
public class TagMapRow
{
    public string MapType { get; set; } = string.Empty;
    public int DNPIndex { get; set; }
    public string TagName { get; set; } = string.Empty;
    public string AlternateTag { get; set; } = string.Empty;
    public double Scale { get; set; } = 1.0;
    public bool Negate { get; set; }
    public bool Concatenate { get; set; }
    public bool InvertSBit { get; set; }
    public bool InvertXBit { get; set; }
}
