using ExperionCrawler.Core.Application.DTOs;
using ExperionCrawler.Core.Domain.Entities;
using ExperionCrawler.Infrastructure.Database;
using System.Collections.Generic;

namespace ExperionCrawler.Core.Application.Interfaces;

// ── Certificate ──────────────────────────────────────────────────────────────

public interface IExperionCertificateService
{
    /// <summary>인증서가 없으면 생성, 있으면 기존 반환</summary>
    Task<ExperionCertResult> EnsureCertificateAsync(
        string applicationUri,
        string clientHostName,
        IEnumerable<string> subjectAltNames,
        string pfxPassword = "");

    bool                  CertificateExists(string clientHostName);
    ExperionCertInfo      GetCertificateInfo(string clientHostName);
}

// ── OPC UA Client ────────────────────────────────────────────────────────────

public interface IExperionOpcClient
{
    Task<ExperionConnectResult>        TestConnectionAsync(ExperionServerConfig cfg);
    Task<ExperionReadResult>           ReadTagAsync(ExperionServerConfig cfg, string nodeId);
    Task<IEnumerable<ExperionReadResult>> ReadTagsAsync(ExperionServerConfig cfg, IEnumerable<string> nodeIds);
    Task<ExperionBrowseResult>         BrowseNodesAsync(ExperionServerConfig cfg, string? startNodeId = null);
    Task<ExperionNodeMapResult>        BrowseAllNodesAsync(ExperionServerConfig cfg, int maxDepth = 10, CancellationToken ct = default);
}

// ── CSV ──────────────────────────────────────────────────────────────────────

public interface IExperionCsvService
{
    Task<string>                        ExportAsync(IEnumerable<ExperionRecord> records, string fileName);
    Task<IEnumerable<ExperionRecord>>   ImportAsync(string filePath);
    IEnumerable<string>                 GetAvailableFiles();
    Task<string>                        ExportNodeMapAsync(IEnumerable<ExperionNodeMapEntry> entries, string fileName);
}

// ── Database ─────────────────────────────────────────────────────────────────

public interface IExperionDbService
{
    Task<bool> InitializeAsync();
    
    // ── TimeScaleDB 하이퍼테이블 ──────────────────────────────────────────────────
    Task<HypertableStatusInfo> GetHypertableStatusAsync();
    Task<HypertableCreateResult> CreateHypertableAsync(HypertableCreateRequest request);
    
    Task<int>  SaveRecordsAsync(IEnumerable<ExperionRecord> records);
    Task<int>  ClearRecordsAsync();
    Task<int>  BuildMasterFromRawAsync(bool truncate = false);
    Task<IEnumerable<ExperionRecord>> GetRecordsAsync(DateTime? from = null, DateTime? to = null, int limit = 1000);
    Task<int>  GetTotalCountAsync();
    Task<IEnumerable<string>> GetNameListAsync();
    Task<NodeMapStats>       GetMasterStatsAsync();
    Task<NodeMapQueryResult> QueryMasterAsync(
        int? minLevel, int? maxLevel, string? nodeClass,
        IEnumerable<string>? names, string? nodeId, string? dataType,
        int limit, int offset);

    // ── RealtimeTable ─────────────────────────────────────────────────────────
    Task<int>  BuildRealtimeTableAsync(IEnumerable<string> names, IEnumerable<string> dataTypes);
    Task<IEnumerable<RealtimePoint>> GetRealtimePointsAsync();
    Task<RealtimePoint> AddRealtimePointAsync(string nodeId);
    Task<bool> DeleteRealtimePointAsync(int id);
    Task<int>  UpdateLiveValueAsync(string nodeId, string? value, DateTime timestamp);
    Task<int>  BatchUpdateLiveValuesAsync(IEnumerable<LiveValueUpdate> updates);

    // ── HistoryTable ──────────────────────────────────────────────────────────
    Task<int> SnapshotToHistoryAsync();
    Task<IEnumerable<string>> GetTagNamesAsync();
    Task<HistoryQueryResult>  QueryHistoryAsync(
        IEnumerable<string> tagNames, DateTime? from, DateTime? to, int limit);

    // ── OPC UA Server 지원 ────────────────────────────────────────────────────
    /// <summary>realtime_table × node_map_master 조인 → nodeId → dataType 사전 반환</summary>
    Task<IReadOnlyDictionary<string, string>> GetRealtimeNodeDataTypesAsync();
}

// ── Realtime Service ─────────────────────────────────────────────────────────

public interface IExperionRealtimeService
{
    Task StartAsync(ExperionServerConfig cfg);
    Task StopAsync();
    RealtimeServiceStatus GetStatus();
    /// <summary>
    /// 구독 중이면 MonitoredItem 핫 추가 후 OPC UA 서버 응답 검증.
    /// 구독 중이지 않으면 (true, "구독 중 아님") 반환.
    /// </summary>
    Task<(bool Success, string Message)> AddMonitoredItemAsync(string nodeId);
}

public record RealtimeServiceStatus(bool Running, int SubscribedCount, string Message);

// ── OPC UA Server ─────────────────────────────────────────────────────────────

public interface IExperionOpcServerService
{
    Task StartServerAsync();
    Task StopServerAsync();
    OpcServerStatus GetStatus();
    void UpdateNodeValue(string tagname, string? value, DateTime timestamp);
    void RebuildAddressSpace(IEnumerable<ExperionCrawler.Core.Domain.Entities.RealtimePoint> points);
}

public record OpcServerStatus(
    bool Running,
    int  ConnectedClientCount,
    int  NodeCount,
    string EndpointUrl,
    DateTime? StartedAt);

// ── Status Code ──────────────────────────────────────────────────────────────

public interface IExperionStatusCodeService
{
    ExperionStatusCodeInfo? GetByHex(string hexCode);
    ExperionStatusCodeInfo? GetByUint(uint statusCode);
    int LoadedCount { get; }
}

// ── Result records ───────────────────────────────────────────────────────────

public record ExperionCertResult  (bool Success, string Message, string? ThumbPrint = null);
public record ExperionCertInfo    (bool Exists, string? SubjectName, DateTime? NotAfter, string? ThumbPrint, string FilePath);
public record ExperionConnectResult(bool Success, string Message, string? SessionId = null, string? PolicyUri = null);
public record ExperionReadResult  (bool Success, string NodeId, object? Value, string StatusCode,
                                   string? ErrorMessage = null, DateTime? Timestamp = null);
public record ExperionBrowseResult(bool Success, IEnumerable<ExperionNodeInfo> Nodes, string? ErrorMessage = null);
public record ExperionNodeInfo    (string NodeId, string DisplayName, string NodeClass, bool HasChildren);
public record ExperionNodeMapEntry(int Level, string NodeClass, string DisplayName, string NodeId, string DataType);
public record ExperionNodeMapResult(bool Success, IEnumerable<ExperionNodeMapEntry> Nodes, int TotalCount, string? ErrorMessage = null);
public record NodeMapStats(int Total, int ObjectCount, int VariableCount, int MaxLevel, IEnumerable<string> DataTypes);
public record NodeMapQueryResult(int Total, IEnumerable<NodeMapMaster> Items);
public record HistoryQueryResult(IEnumerable<string> TagNames, IEnumerable<HistoryRow> Rows);
public record HistoryRow(DateTime RecordedAt, IReadOnlyDictionary<string, string?> Values);
public record LiveValueUpdate(string NodeId, string? Value, DateTime Timestamp);
