#nullable enable

using System.Data;

namespace MBN_STOCK_WEBVIEW.Core.Playout.Scenes;

/// <summary>
/// Narrow compatibility rules shared only by the four GraphE INPUT_* scenes.
/// Raw editor values remain unchanged; these rules apply to the typed playout
/// projection after a fresh database read.
/// </summary>
internal static class LegacyManualFinancialStorageCompatibility
{
    public static string NormalizeQuarterLabel(string value)
    {
        ArgumentNullException.ThrowIfNull(value);

        // The legacy scene passed quarter labels directly to K3D. A trailing
        // horizontal tab was visually inert, but the current scene text guard
        // correctly rejects control characters. Remove only that inert suffix;
        // any remaining label controls are rejected by the scene text guard.
        return value.TrimEnd('\t');
    }

    public static string RequiredQuarterStorageString(DataRow row, string columnName)
    {
        ArgumentNullException.ThrowIfNull(row);
        if (!row.Table.Columns.Contains(columnName) ||
            row[columnName] is not string value ||
            value.Length > 4_096)
        {
            throw InvalidResult();
        }

        return value;
    }

    public static DataRow SingleEquivalentSceneRow(
        DataTable? table,
        params string[] sceneDrivingColumns)
    {
        ArgumentNullException.ThrowIfNull(sceneDrivingColumns);
        if (table is null || table.Rows.Count == 0 ||
            table.Columns.Count != sceneDrivingColumns.Length)
        {
            throw InvalidResult();
        }

        for (var index = 0; index < sceneDrivingColumns.Length; index++)
        {
            if (!string.Equals(
                    table.Columns[index].ColumnName,
                    sceneDrivingColumns[index],
                    StringComparison.OrdinalIgnoreCase))
            {
                throw InvalidResult();
            }
        }

        var first = table.Rows[0];
        for (var rowIndex = 1; rowIndex < table.Rows.Count; rowIndex++)
        {
            var candidate = table.Rows[rowIndex];
            foreach (var column in sceneDrivingColumns)
            {
                if (!EquivalentStoredValue(first[column], candidate[column]))
                {
                    throw InvalidResult();
                }
            }
        }

        return first;
    }

    private static bool EquivalentStoredValue(object? left, object? right)
    {
        var leftIsNull = left is null or DBNull;
        var rightIsNull = right is null or DBNull;
        if (leftIsNull || rightIsNull)
        {
            return leftIsNull && rightIsNull;
        }

        return left is string leftText &&
            right is string rightText &&
            string.Equals(leftText, rightText, StringComparison.Ordinal);
    }

    private static LegacySceneDataException InvalidResult() =>
        new("The manual-financial scene query did not return one equivalent row set.");
}
