using System.Data;
using System.Data.Common;
using Hc900Crawler.Core.Application.Feedforward;
using Hc900Crawler.Infrastructure.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace Hc900Crawler.Infrastructure.Control;

public sealed class FeedforwardAuditService : IFeedforwardAuditService
{
    private readonly Hc900DbContext _ctx;
    private readonly ILogger<FeedforwardAuditService> _logger;

    public FeedforwardAuditService(Hc900DbContext ctx, ILogger<FeedforwardAuditService> logger)
    { _ctx = ctx; _logger = logger; }

    public async Task LogAsync(FfActionLogEntry entry, CancellationToken ct = default)
    {
        try
        {
            var conn = _ctx.Database.GetDbConnection();
            if (conn.State != ConnectionState.Open) await conn.OpenAsync(ct);
            await using var cmd = conn.CreateCommand();
            cmd.CommandText = """
                INSERT INTO ff_operator_action
                    (column_id, stream_key, action_type, sp_value, node_id, result, writeguard_reason, operator_name, created_at)
                VALUES (@colId, @streamKey, @action, @spVal, @nodeId, @result, @wgReason, @op, NOW())
                """;
            P(cmd, "@colId", entry.ColumnId);
            P(cmd, "@streamKey", entry.StreamKey);
            P(cmd, "@action", entry.ActionType);
            P(cmd, "@spVal", entry.SpValue.HasValue ? (object)entry.SpValue.Value : DBNull.Value);
            P(cmd, "@nodeId", entry.NodeId);
            P(cmd, "@result", entry.Result ?? "unknown");
            P(cmd, "@wgReason", entry.WriteguardReason);
            P(cmd, "@op", entry.OperatorName);
            await cmd.ExecuteNonQueryAsync(ct);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "[FfAudit] 로그 기록 실패 column={ColId}", entry.ColumnId);
        }
    }

    public async Task<IReadOnlyList<dynamic>> QueryAsync(int? columnId = null, int limit = 50, CancellationToken ct = default)
    {
        var conn = _ctx.Database.GetDbConnection();
        if (conn.State != ConnectionState.Open) await conn.OpenAsync(ct);
        await using var cmd = conn.CreateCommand();
        cmd.CommandText = columnId.HasValue
            ? "SELECT * FROM ff_operator_action WHERE column_id=@colId ORDER BY created_at DESC LIMIT @lim"
            : "SELECT * FROM ff_operator_action ORDER BY created_at DESC LIMIT @lim";
        if (columnId.HasValue) P(cmd, "@colId", columnId.Value);
        P(cmd, "@lim", limit);
        var results = new List<dynamic>();
        await using var rd = await cmd.ExecuteReaderAsync(ct);
        while (await rd.ReadAsync(ct))
        {
            results.Add(new
            {
                id = rd.GetInt64(0),
                columnId = rd.GetInt32(1),
                streamKey = rd.IsDBNull(2) ? null : rd.GetString(2),
                actionType = rd.GetString(3),
                spValue = rd.IsDBNull(4) ? (double?)null : rd.GetDouble(4),
                nodeId = rd.IsDBNull(5) ? null : rd.GetString(5),
                result = rd.GetString(6),
                writeguardReason = rd.IsDBNull(7) ? null : rd.GetString(7),
                operatorName = rd.IsDBNull(8) ? null : rd.GetString(8),
                createdAt = rd.GetDateTime(9)
            });
        }
        return results;
    }

    private static void P(DbCommand cmd, string name, object? val)
    {
        var p = cmd.CreateParameter();
        p.ParameterName = name;
        p.Value = val ?? DBNull.Value;
        cmd.Parameters.Add(p);
    }
}
