public static class MimicCsvReader
{
    public static IEnumerable<T> Read<T>(
        string filePath,
        Func<string[], Dictionary<string, int>, T?> parser,
        Func<string[], Dictionary<string, int>, bool>? filter = null)
    {
        using var reader = new StreamReader(filePath);
        var headerLine = reader.ReadLine();
        if (headerLine is null) yield break;

        var headers = BuildHeaderIndex(headerLine);

        while (reader.ReadLine() is { } line)
        {
            if (string.IsNullOrWhiteSpace(line)) continue;
            var fields = line.Split(',');

            if (filter is not null && !filter(fields, headers))
                continue;

            var record = parser(fields, headers);
            if (record is not null)
                yield return record;
        }
    }

    public static List<T> ReadAll<T>(
        string filePath,
        Func<string[], Dictionary<string, int>, T?> parser)
    {
        return Read(filePath, parser).ToList();
    }

    private static Dictionary<string, int> BuildHeaderIndex(string headerLine)
    {
        var headers = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
        var columns = headerLine.Split(',');
        for (var i = 0; i < columns.Length; i++)
            headers[columns[i].Trim()] = i;
        return headers;
    }

    public static string Col(string[] fields, Dictionary<string, int> headers, string name)
    {
        return headers.TryGetValue(name, out var idx) && idx < fields.Length
            ? fields[idx].Trim()
            : string.Empty;
    }

    public static int? ColInt(string[] fields, Dictionary<string, int> headers, string name)
    {
        var val = Col(fields, headers, name);
        return int.TryParse(val, out var result) ? result : null;
    }

    public static decimal? ColDecimal(string[] fields, Dictionary<string, int> headers, string name)
    {
        var val = Col(fields, headers, name);
        return decimal.TryParse(val, System.Globalization.NumberStyles.Any,
            System.Globalization.CultureInfo.InvariantCulture, out var result) ? result : null;
    }

    public static DateTime? ColDateTime(string[] fields, Dictionary<string, int> headers, string name)
    {
        var val = Col(fields, headers, name);
        return DateTime.TryParse(val, System.Globalization.CultureInfo.InvariantCulture,
            System.Globalization.DateTimeStyles.None, out var result) ? result : null;
    }
}
