using AnotherReplayReader.ReplayFile;
using System;
using System.Collections.Generic;
using System.Linq;

namespace AnotherReplayReader.Apm
{
    internal class DataRow
    {
        public const string AverageApmRow = "APM(整局游戏)";
        public const string PartialApmRow = "APM(当前时间段)";

        public string Name { get; }
        public bool IsDisabled { get; }
        public DataValue Player1Value => _values[0];
        public DataValue Player2Value => _values[1];
        public DataValue Player3Value => _values[2];
        public DataValue Player4Value => _values[3];
        public DataValue Player5Value => _values[4];
        public DataValue Player6Value => _values[5];

        private readonly IReadOnlyList<DataValue> _values;

        public DataRow(string name,
                       IEnumerable<string> values,
                       bool isDisabled = false)
        {
            Name = name;
            IsDisabled = isDisabled;

            if (values.Count() < 6)
            {
                values = values.Concat(new string[6 - values.Count()]);
            }
            _values = values.Select(x => new DataValue(x)).ToArray();
        }

        public static List<DataRow> GetList(ApmPlotter plotter,
                                            ApmPlotterFilterOptions options,
                                            TimeSpan begin,
                                            TimeSpan end,
                                            out int apmRowIndex)
        {
            // these commands should appear in this order by default
            var orderedCommands = new List<byte>();
            orderedCommands.AddRange(
            [
                0xF5,
                0xF8,
                0x2A,
                0xFA,
                0xFB,
                0x07,
                0x08,
                0x05,
                0x06,
                0x09,
                0x00,
                0x0A,
                0x03,
                0x04,
                0x28,
                0x29,
                0x0D,
                0x0E,
                0x15,
                0x14,
                0x36,
                0x16,
                0x2C,
                0x1A,
                0x4E,
                0xFE,
                0xFF,
                0x32,
                0x2E,
                0x2F,
                0x4B,
                0x4C,
                0x02,
                0x0C,
                0x10,
            ]);
            orderedCommands.AddRange(RA3Commands.AutoCommands);
            orderedCommands.AddRange(RA3Commands.UnknownCommands);

            var dataList = new List<DataRow>
            {
                new("ID", plotter.Players.Select(x => x.PlayerName))
            };
            var isPartial = begin > TimeSpan.Zero || end <= plotter.ReplayLength;
            if (isPartial)
            {
                string GetStatus(Player player, int i)
                {
                    if (player.IsComputer)
                    {
                        return "这是 AI";
                    }
                    if (begin < plotter.StricterPlayerLifes[i])
                    {
                        return "存活";
                    }
                    return begin < plotter.PlayerLifes[i]
                            ? "变身天眼帝国,或双手离开键盘"
                            : "可能已离开房间";
                }
                dataList.Add(new("存活状态(推测)", plotter.Players.Select(GetStatus)));
            }
            apmRowIndex = dataList.Count;
            // kill-death ratio
            if (plotter.Replay.Footer?.TryGetKillDeathRatios() is { } kdRatios)
            {
                var texts = kdRatios
                    .Take(plotter.Players.Length)
                    .Select(x => $"{x:0.##}");
                dataList.Add(new("击杀阵亡比(存疑)", texts));
            }
            // get commands
            var commandCounts = plotter.GetCommandCounts(begin, end);
            // add commands in the order specified by the list
            foreach (var command in orderedCommands)
            {
                var counts = commandCounts.TryGetValue(command, out var stored)
                    ? stored
                    : new int[plotter.Players.Length];
                if (!isPartial || counts.Any(x => x > 0))
                {
                    dataList.Add(new(RA3Commands.GetCommandName(command),
                                     counts.Select(x => $"{x}"),
                                     options.ShouldSkip(command)));
                }
                commandCounts.Remove(command);
            }
            // add other commands
            foreach (var commandCount in commandCounts)
            {
                dataList.Add(new(RA3Commands.GetCommandName(commandCount.Key),
                                 commandCount.Value.Select(x => $"{x}"),
                                 options.ShouldSkip(commandCount.Key)));
            }

            return dataList;
        }
    }
}