using System;
using MessagePack;

namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Ipc;

// ============================================================================
// Wire DTOs for the sidecar pipe protocol. The sidecar speaks its own legacy
// shape (List<HistorianSample> etc.) — the .NET 10 client (PR 3.4) translates
// to / from Core.Abstractions.DataValueSnapshot + HistoricalEvent.
//
// Timestamps cross the wire as DateTime ticks (long) to dodge MessagePack's
// DateTime kind/timezone quirks; both sides convert with DateTime(ticks, Utc).
// ============================================================================

/// <summary>Single historical data point. Quality is the raw OPC DA byte; client maps to OPC UA StatusCode.</summary>
[MessagePackObject]
public sealed class HistorianSampleDto
{
    /// <summary>MessagePack-serialized value bytes. Client deserializes per the tag's mx_data_type.</summary>
    [Key(0)] public byte[]? ValueBytes { get; set; }

    /// <summary>Raw OPC DA quality byte from the historian SDK (low 8 bits of OpcQuality).</summary>
    [Key(1)] public byte Quality { get; set; }

    /// <summary>Gets or sets the timestamp in UTC ticks.</summary>
    [Key(2)] public long TimestampUtcTicks { get; set; }
}

/// <summary>Aggregate bucket; <c>Value</c> is null when the aggregate is unavailable for the bucket.</summary>
[MessagePackObject]
public sealed class HistorianAggregateSampleDto
{
    /// <summary>Gets or sets the aggregate value.</summary>
    [Key(0)] public double? Value { get; set; }

    /// <summary>Gets or sets the timestamp in UTC ticks.</summary>
    [Key(1)] public long TimestampUtcTicks { get; set; }
}

/// <summary>Historian event row.</summary>
[MessagePackObject]
public sealed class HistorianEventDto
{
    /// <summary>Gets or sets the event identifier.</summary>
    [Key(0)] public string EventId { get; set; } = string.Empty;

    /// <summary>Gets or sets the event source name.</summary>
    [Key(1)] public string? Source { get; set; }

    /// <summary>Gets or sets the event time in UTC ticks.</summary>
    [Key(2)] public long EventTimeUtcTicks { get; set; }

    /// <summary>Gets or sets the received time in UTC ticks.</summary>
    [Key(3)] public long ReceivedTimeUtcTicks { get; set; }

    /// <summary>Gets or sets the display text.</summary>
    [Key(4)] public string? DisplayText { get; set; }

    /// <summary>Gets or sets the severity.</summary>
    [Key(5)] public ushort Severity { get; set; }
}

/// <summary>Alarm event to persist back into the historian event store.</summary>
[MessagePackObject]
public sealed class AlarmHistorianEventDto
{
    /// <summary>Gets or sets the event identifier.</summary>
    [Key(0)] public string EventId { get; set; } = string.Empty;

    /// <summary>Gets or sets the source name.</summary>
    [Key(1)] public string SourceName { get; set; } = string.Empty;

    /// <summary>Gets or sets the condition identifier.</summary>
    [Key(2)] public string? ConditionId { get; set; }

    /// <summary>Gets or sets the alarm type.</summary>
    [Key(3)] public string AlarmType { get; set; } = string.Empty;

    /// <summary>Gets or sets the alarm message.</summary>
    [Key(4)] public string? Message { get; set; }

    /// <summary>Gets or sets the severity.</summary>
    [Key(5)] public ushort Severity { get; set; }

    /// <summary>Gets or sets the event time in UTC ticks.</summary>
    [Key(6)] public long EventTimeUtcTicks { get; set; }

    /// <summary>Gets or sets the acknowledgment comment.</summary>
    [Key(7)] public string? AckComment { get; set; }
}

// ===== Read Raw =====

[MessagePackObject]
public sealed class ReadRawRequest
{
    /// <summary>Gets or sets the tag name.</summary>
    [Key(0)] public string TagName { get; set; } = string.Empty;

    /// <summary>Gets or sets the start time in UTC ticks.</summary>
    [Key(1)] public long StartUtcTicks { get; set; }

    /// <summary>Gets or sets the end time in UTC ticks.</summary>
    [Key(2)] public long EndUtcTicks { get; set; }

    /// <summary>Gets or sets the maximum number of values to return.</summary>
    [Key(3)] public int MaxValues { get; set; }

    /// <summary>Gets or sets the correlation identifier.</summary>
    [Key(4)] public string CorrelationId { get; set; } = string.Empty;
}

[MessagePackObject]
public sealed class ReadRawReply
{
    /// <summary>Gets or sets the correlation identifier.</summary>
    [Key(0)] public string CorrelationId { get; set; } = string.Empty;

    /// <summary>Gets or sets a value indicating whether the request succeeded.</summary>
    [Key(1)] public bool Success { get; set; }

    /// <summary>Gets or sets the error message if the request failed.</summary>
    [Key(2)] public string? Error { get; set; }

    /// <summary>Gets or sets the historical samples.</summary>
    [Key(3)] public HistorianSampleDto[] Samples { get; set; } = Array.Empty<HistorianSampleDto>();
}

// ===== Read Processed =====

[MessagePackObject]
public sealed class ReadProcessedRequest
{
    /// <summary>Gets or sets the tag name.</summary>
    [Key(0)] public string TagName { get; set; } = string.Empty;

    /// <summary>Gets or sets the start time in UTC ticks.</summary>
    [Key(1)] public long StartUtcTicks { get; set; }

    /// <summary>Gets or sets the end time in UTC ticks.</summary>
    [Key(2)] public long EndUtcTicks { get; set; }

    /// <summary>Gets or sets the interval in milliseconds.</summary>
    [Key(3)] public double IntervalMs { get; set; }

    /// <summary>
    ///     Wonderware AnalogSummary column name: "Average", "Minimum", "Maximum", "ValueCount".
    ///     The .NET 10 client maps OPC UA aggregate enum → column.
    /// </summary>
    [Key(4)] public string AggregateColumn { get; set; } = string.Empty;

    /// <summary>Gets or sets the correlation identifier.</summary>
    [Key(5)] public string CorrelationId { get; set; } = string.Empty;
}

[MessagePackObject]
public sealed class ReadProcessedReply
{
    /// <summary>Gets or sets the correlation identifier.</summary>
    [Key(0)] public string CorrelationId { get; set; } = string.Empty;

    /// <summary>Gets or sets a value indicating whether the request succeeded.</summary>
    [Key(1)] public bool Success { get; set; }

    /// <summary>Gets or sets the error message if the request failed.</summary>
    [Key(2)] public string? Error { get; set; }

    /// <summary>Gets or sets the aggregate sample buckets.</summary>
    [Key(3)] public HistorianAggregateSampleDto[] Buckets { get; set; } = Array.Empty<HistorianAggregateSampleDto>();
}

// ===== Read At-Time =====

[MessagePackObject]
public sealed class ReadAtTimeRequest
{
    /// <summary>Gets or sets the tag name.</summary>
    [Key(0)] public string TagName { get; set; } = string.Empty;

    /// <summary>Gets or sets the timestamps in UTC ticks.</summary>
    [Key(1)] public long[] TimestampsUtcTicks { get; set; } = Array.Empty<long>();

    /// <summary>Gets or sets the correlation identifier.</summary>
    [Key(2)] public string CorrelationId { get; set; } = string.Empty;
}

[MessagePackObject]
public sealed class ReadAtTimeReply
{
    /// <summary>Gets or sets the correlation identifier.</summary>
    [Key(0)] public string CorrelationId { get; set; } = string.Empty;

    /// <summary>Gets or sets a value indicating whether the request succeeded.</summary>
    [Key(1)] public bool Success { get; set; }

    /// <summary>Gets or sets the error message if the request failed.</summary>
    [Key(2)] public string? Error { get; set; }

    /// <summary>Gets or sets the historical samples.</summary>
    [Key(3)] public HistorianSampleDto[] Samples { get; set; } = Array.Empty<HistorianSampleDto>();
}

// ===== Read Events =====

[MessagePackObject]
public sealed class ReadEventsRequest
{
    /// <summary>Gets or sets the source name.</summary>
    [Key(0)] public string? SourceName { get; set; }

    /// <summary>Gets or sets the start time in UTC ticks.</summary>
    [Key(1)] public long StartUtcTicks { get; set; }

    /// <summary>Gets or sets the end time in UTC ticks.</summary>
    [Key(2)] public long EndUtcTicks { get; set; }

    /// <summary>Gets or sets the maximum number of events to return.</summary>
    [Key(3)] public int MaxEvents { get; set; }

    /// <summary>Gets or sets the correlation identifier.</summary>
    [Key(4)] public string CorrelationId { get; set; } = string.Empty;
}

[MessagePackObject]
public sealed class ReadEventsReply
{
    /// <summary>Gets or sets the correlation identifier.</summary>
    [Key(0)] public string CorrelationId { get; set; } = string.Empty;

    /// <summary>Gets or sets a value indicating whether the request succeeded.</summary>
    [Key(1)] public bool Success { get; set; }

    /// <summary>Gets or sets the error message if the request failed.</summary>
    [Key(2)] public string? Error { get; set; }

    /// <summary>Gets or sets the historian events.</summary>
    [Key(3)] public HistorianEventDto[] Events { get; set; } = Array.Empty<HistorianEventDto>();
}

// ===== Write Alarm Events =====

[MessagePackObject]
public sealed class WriteAlarmEventsRequest
{
    /// <summary>Gets or sets the alarm events to write.</summary>
    [Key(0)] public AlarmHistorianEventDto[] Events { get; set; } = Array.Empty<AlarmHistorianEventDto>();

    /// <summary>Gets or sets the correlation identifier.</summary>
    [Key(1)] public string CorrelationId { get; set; } = string.Empty;
}

[MessagePackObject]
public sealed class WriteAlarmEventsReply
{
    /// <summary>Gets or sets the correlation identifier.</summary>
    [Key(0)] public string CorrelationId { get; set; } = string.Empty;

    /// <summary>Gets or sets a value indicating whether the request succeeded.</summary>
    [Key(1)] public bool Success { get; set; }

    /// <summary>Gets or sets the error message if the request failed.</summary>
    [Key(2)] public string? Error { get; set; }

    /// <summary>Per-event success flag, parallel to <see cref="WriteAlarmEventsRequest.Events"/>.</summary>
    [Key(3)] public bool[] PerEventOk { get; set; } = Array.Empty<bool>();
}
