using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Threading;
using System.Threading.Tasks;

namespace ZB.MOM.WW.LmxProxy.Client.Domain;

// ────────────────────────────────────────────────────────────────
// Service contract
// ────────────────────────────────────────────────────────────────

/// <summary>
/// Code-first gRPC service contract for SCADA operations.
/// </summary>
[ServiceContract(Name = "scada.ScadaService")]
public interface IScadaService
{
	/// <summary>Establishes a connection with the SCADA service.</summary>
	ValueTask<ConnectResponse> ConnectAsync(ConnectRequest request);

	/// <summary>Terminates a SCADA service connection.</summary>
	ValueTask<DisconnectResponse> DisconnectAsync(DisconnectRequest request);

	/// <summary>Retrieves the current state of a SCADA connection.</summary>
	ValueTask<GetConnectionStateResponse> GetConnectionStateAsync(GetConnectionStateRequest request);

	/// <summary>Reads a single tag value from the SCADA system.</summary>
	ValueTask<ReadResponse> ReadAsync(ReadRequest request);

	/// <summary>Reads multiple tag values from the SCADA system in a batch operation.</summary>
	ValueTask<ReadBatchResponse> ReadBatchAsync(ReadBatchRequest request);

	/// <summary>Writes a single value to a tag in the SCADA system.</summary>
	ValueTask<WriteResponse> WriteAsync(WriteRequest request);

	/// <summary>Writes multiple values to tags in the SCADA system in a batch operation.</summary>
	ValueTask<WriteBatchResponse> WriteBatchAsync(WriteBatchRequest request);

	/// <summary>Writes multiple values and waits for a completion flag before returning.</summary>
	ValueTask<WriteBatchAndWaitResponse> WriteBatchAndWaitAsync(WriteBatchAndWaitRequest request);

	/// <summary>Subscribes to real-time value changes from specified tags.</summary>
	IAsyncEnumerable<VtqMessage> SubscribeAsync(SubscribeRequest request, CancellationToken cancellationToken = default);

	/// <summary>Validates an API key for authentication.</summary>
	ValueTask<CheckApiKeyResponse> CheckApiKeyAsync(CheckApiKeyRequest request);
}

// ────────────────────────────────────────────────────────────────
// VTQ message
// ────────────────────────────────────────────────────────────────

/// <summary>
/// Value-Timestamp-Quality message transmitted over gRPC.
/// All values are string-encoded; timestamps are UTC ticks.
/// </summary>
[DataContract]
public class VtqMessage
{
	/// <summary>Tag address.</summary>
	[DataMember(Order = 1)]
	public string Tag { get; set; } = string.Empty;

	/// <summary>Value encoded as a string.</summary>
	[DataMember(Order = 2)]
	public string Value { get; set; } = string.Empty;

	/// <summary>UTC timestamp as DateTime.Ticks (100ns intervals since 0001-01-01).</summary>
	[DataMember(Order = 3)]
	public long TimestampUtcTicks { get; set; }

	/// <summary>Quality string: "Good", "Uncertain", or "Bad".</summary>
	[DataMember(Order = 4)]
	public string Quality { get; set; } = string.Empty;
}

// ────────────────────────────────────────────────────────────────
// Connect
// ────────────────────────────────────────────────────────────────

/// <summary>Request to establish a session with the proxy server.</summary>
[DataContract]
public class ConnectRequest
{
	/// <summary>Client identifier (e.g., "ScadaLink-{guid}").</summary>
	[DataMember(Order = 1)]
	public string ClientId { get; set; } = string.Empty;

	/// <summary>API key for authentication (empty if none required).</summary>
	[DataMember(Order = 2)]
	public string ApiKey { get; set; } = string.Empty;
}

/// <summary>Response from a Connect call.</summary>
[DataContract]
public class ConnectResponse
{
	/// <summary>Whether the connection was established successfully.</summary>
	[DataMember(Order = 1)]
	public bool Success { get; set; }

	/// <summary>Status or error message.</summary>
	[DataMember(Order = 2)]
	public string Message { get; set; } = string.Empty;

	/// <summary>Session ID (32-char hex GUID). Only valid when <see cref="Success"/> is <c>true</c>.</summary>
	[DataMember(Order = 3)]
	public string SessionId { get; set; } = string.Empty;
}

// ────────────────────────────────────────────────────────────────
// Disconnect
// ────────────────────────────────────────────────────────────────

/// <summary>Request to terminate a session.</summary>
[DataContract]
public class DisconnectRequest
{
	/// <summary>Active session ID to disconnect.</summary>
	[DataMember(Order = 1)]
	public string SessionId { get; set; } = string.Empty;
}

/// <summary>Response from a Disconnect call.</summary>
[DataContract]
public class DisconnectResponse
{
	/// <summary>Whether the disconnect succeeded.</summary>
	[DataMember(Order = 1)]
	public bool Success { get; set; }

	/// <summary>Status or error message.</summary>
	[DataMember(Order = 2)]
	public string Message { get; set; } = string.Empty;
}

// ────────────────────────────────────────────────────────────────
// GetConnectionState
// ────────────────────────────────────────────────────────────────

/// <summary>Request to query connection state for a session.</summary>
[DataContract]
public class GetConnectionStateRequest
{
	/// <summary>Session ID to query.</summary>
	[DataMember(Order = 1)]
	public string SessionId { get; set; } = string.Empty;
}

/// <summary>Response with connection state information.</summary>
[DataContract]
public class GetConnectionStateResponse
{
	/// <summary>Whether the session is currently connected.</summary>
	[DataMember(Order = 1)]
	public bool IsConnected { get; set; }

	/// <summary>Client identifier for this session.</summary>
	[DataMember(Order = 2)]
	public string ClientId { get; set; } = string.Empty;

	/// <summary>UTC ticks when the connection was established.</summary>
	[DataMember(Order = 3)]
	public long ConnectedSinceUtcTicks { get; set; }
}

// ────────────────────────────────────────────────────────────────
// Read
// ────────────────────────────────────────────────────────────────

/// <summary>Request to read a single tag.</summary>
[DataContract]
public class ReadRequest
{
	/// <summary>Valid session ID.</summary>
	[DataMember(Order = 1)]
	public string SessionId { get; set; } = string.Empty;

	/// <summary>Tag address to read.</summary>
	[DataMember(Order = 2)]
	public string Tag { get; set; } = string.Empty;
}

/// <summary>Response from a single-tag Read call.</summary>
[DataContract]
public class ReadResponse
{
	/// <summary>Whether the read succeeded.</summary>
	[DataMember(Order = 1)]
	public bool Success { get; set; }

	/// <summary>Error message if the read failed.</summary>
	[DataMember(Order = 2)]
	public string Message { get; set; } = string.Empty;

	/// <summary>The value-timestamp-quality result.</summary>
	[DataMember(Order = 3)]
	public VtqMessage? Vtq { get; set; }
}

// ────────────────────────────────────────────────────────────────
// ReadBatch
// ────────────────────────────────────────────────────────────────

/// <summary>Request to read multiple tags in a single round-trip.</summary>
[DataContract]
public class ReadBatchRequest
{
	/// <summary>Valid session ID.</summary>
	[DataMember(Order = 1)]
	public string SessionId { get; set; } = string.Empty;

	/// <summary>Tag addresses to read.</summary>
	[DataMember(Order = 2)]
	public List<string> Tags { get; set; } = [];
}

/// <summary>Response from a batch Read call.</summary>
[DataContract]
public class ReadBatchResponse
{
	/// <summary>False if any tag read failed.</summary>
	[DataMember(Order = 1)]
	public bool Success { get; set; }

	/// <summary>Error message.</summary>
	[DataMember(Order = 2)]
	public string Message { get; set; } = string.Empty;

	/// <summary>VTQ results in the same order as the request tags.</summary>
	[DataMember(Order = 3)]
	public List<VtqMessage> Vtqs { get; set; } = [];
}

// ────────────────────────────────────────────────────────────────
// Write
// ────────────────────────────────────────────────────────────────

/// <summary>Request to write a single tag value.</summary>
[DataContract]
public class WriteRequest
{
	/// <summary>Valid session ID.</summary>
	[DataMember(Order = 1)]
	public string SessionId { get; set; } = string.Empty;

	/// <summary>Tag address to write.</summary>
	[DataMember(Order = 2)]
	public string Tag { get; set; } = string.Empty;

	/// <summary>Value as a string (parsed server-side).</summary>
	[DataMember(Order = 3)]
	public string Value { get; set; } = string.Empty;
}

/// <summary>Response from a single-tag Write call.</summary>
[DataContract]
public class WriteResponse
{
	/// <summary>Whether the write succeeded.</summary>
	[DataMember(Order = 1)]
	public bool Success { get; set; }

	/// <summary>Status or error message.</summary>
	[DataMember(Order = 2)]
	public string Message { get; set; } = string.Empty;
}

// ────────────────────────────────────────────────────────────────
// WriteItem / WriteResult
// ────────────────────────────────────────────────────────────────

/// <summary>A single tag-value pair for batch write operations.</summary>
[DataContract]
public class WriteItem
{
	/// <summary>Tag address.</summary>
	[DataMember(Order = 1)]
	public string Tag { get; set; } = string.Empty;

	/// <summary>Value as a string.</summary>
	[DataMember(Order = 2)]
	public string Value { get; set; } = string.Empty;
}

/// <summary>Per-item result from a batch write operation.</summary>
[DataContract]
public class WriteResult
{
	/// <summary>Tag address that was written.</summary>
	[DataMember(Order = 1)]
	public string Tag { get; set; } = string.Empty;

	/// <summary>Whether the individual write succeeded.</summary>
	[DataMember(Order = 2)]
	public bool Success { get; set; }

	/// <summary>Error message for this item, if any.</summary>
	[DataMember(Order = 3)]
	public string Message { get; set; } = string.Empty;
}

// ────────────────────────────────────────────────────────────────
// WriteBatch
// ────────────────────────────────────────────────────────────────

/// <summary>Request to write multiple tag values in a single round-trip.</summary>
[DataContract]
public class WriteBatchRequest
{
	/// <summary>Valid session ID.</summary>
	[DataMember(Order = 1)]
	public string SessionId { get; set; } = string.Empty;

	/// <summary>Tag-value pairs to write.</summary>
	[DataMember(Order = 2)]
	public List<WriteItem> Items { get; set; } = [];
}

/// <summary>Response from a batch Write call.</summary>
[DataContract]
public class WriteBatchResponse
{
	/// <summary>Overall success — false if any item failed.</summary>
	[DataMember(Order = 1)]
	public bool Success { get; set; }

	/// <summary>Status or error message.</summary>
	[DataMember(Order = 2)]
	public string Message { get; set; } = string.Empty;

	/// <summary>Per-item write results.</summary>
	[DataMember(Order = 3)]
	public List<WriteResult> Results { get; set; } = [];
}

// ────────────────────────────────────────────────────────────────
// WriteBatchAndWait
// ────────────────────────────────────────────────────────────────

/// <summary>
/// Request to write multiple tag values then poll a flag tag
/// until it matches an expected value or the timeout expires.
/// </summary>
[DataContract]
public class WriteBatchAndWaitRequest
{
	/// <summary>Valid session ID.</summary>
	[DataMember(Order = 1)]
	public string SessionId { get; set; } = string.Empty;

	/// <summary>Tag-value pairs to write.</summary>
	[DataMember(Order = 2)]
	public List<WriteItem> Items { get; set; } = [];

	/// <summary>Tag to poll after writes complete.</summary>
	[DataMember(Order = 3)]
	public string FlagTag { get; set; } = string.Empty;

	/// <summary>Expected value for the flag tag (string comparison).</summary>
	[DataMember(Order = 4)]
	public string FlagValue { get; set; } = string.Empty;

	/// <summary>Timeout in milliseconds (default 5000 if &lt;= 0).</summary>
	[DataMember(Order = 5)]
	public int TimeoutMs { get; set; }

	/// <summary>Poll interval in milliseconds (default 100 if &lt;= 0).</summary>
	[DataMember(Order = 6)]
	public int PollIntervalMs { get; set; }
}

/// <summary>Response from a WriteBatchAndWait call.</summary>
[DataContract]
public class WriteBatchAndWaitResponse
{
	/// <summary>Overall operation success.</summary>
	[DataMember(Order = 1)]
	public bool Success { get; set; }

	/// <summary>Status or error message.</summary>
	[DataMember(Order = 2)]
	public string Message { get; set; } = string.Empty;

	/// <summary>Per-item write results.</summary>
	[DataMember(Order = 3)]
	public List<WriteResult> WriteResults { get; set; } = [];

	/// <summary>Whether the flag tag matched the expected value before timeout.</summary>
	[DataMember(Order = 4)]
	public bool FlagReached { get; set; }

	/// <summary>Total elapsed time in milliseconds.</summary>
	[DataMember(Order = 5)]
	public int ElapsedMs { get; set; }
}

// ────────────────────────────────────────────────────────────────
// Subscribe
// ────────────────────────────────────────────────────────────────

/// <summary>Request to subscribe to value change notifications on one or more tags.</summary>
[DataContract]
public class SubscribeRequest
{
	/// <summary>Valid session ID.</summary>
	[DataMember(Order = 1)]
	public string SessionId { get; set; } = string.Empty;

	/// <summary>Tag addresses to monitor.</summary>
	[DataMember(Order = 2)]
	public List<string> Tags { get; set; } = [];

	/// <summary>Backend sampling interval in milliseconds.</summary>
	[DataMember(Order = 3)]
	public int SamplingMs { get; set; }
}

// ────────────────────────────────────────────────────────────────
// CheckApiKey
// ────────────────────────────────────────────────────────────────

/// <summary>Request to validate an API key without creating a session.</summary>
[DataContract]
public class CheckApiKeyRequest
{
	/// <summary>API key to validate.</summary>
	[DataMember(Order = 1)]
	public string ApiKey { get; set; } = string.Empty;
}

/// <summary>Response from an API key validation check.</summary>
[DataContract]
public class CheckApiKeyResponse
{
	/// <summary>Whether the API key is valid.</summary>
	[DataMember(Order = 1)]
	public bool IsValid { get; set; }

	/// <summary>Validation message.</summary>
	[DataMember(Order = 2)]
	public string Message { get; set; } = string.Empty;
}
