@using SharedLibraryCore.Configuration
@using Data.Models.Client.Stats
@using Stats.Helpers
@using Data.Models.Client
@using Data.Models.Client.Stats.Reference
@using Humanizer
@using Humanizer.Localisation
@using IW4MAdmin.Plugins.Stats
@using WebfrontCore.ViewModels
@using System.Text.Json
@using IW4MAdmin.Plugins.Stats.Web.Dtos
@model Stats.Dtos.AdvancedStatsInfo

@{
    ViewBag.Title = ViewBag.Localization["WEBFRONT_ADV_STATS_TITLE"];
    ViewBag.Description = Model.ClientName.StripColors();

    const string headshotKey = "MOD_HEAD_SHOT";
    const string headshotKey2 = "headshot";
    const string meleeKey = "MOD_MELEE";

    var suicideKeys = new[] { "MOD_SUICIDE", "MOD_FALLING" };
    // if they've not copied default settings config this could be null
    var config = (GameStringConfiguration)ViewBag.Config ?? new GameStringConfiguration();

    string GetWeaponNameForHit(EFClientHitStatistic stat)
    {
        if (stat == null)
        {
            return null;
        }
        var rebuiltName = stat.RebuildWeaponName();
        var name = config.GetStringForGame(rebuiltName, stat.Weapon?.Game);
        return !rebuiltName.Equals(name, StringComparison.InvariantCultureIgnoreCase)
            ? name
            : config.GetStringForGame(stat.Weapon.Name, stat.Weapon.Game);
    }

    string GetWeaponAttachmentName(EFWeaponAttachmentCombo attachment)
    {
        if (attachment == null)
        {
            return null;
        }

        var attachmentText = string.Join(" + ", new[]
        {
            config.GetStringForGame(attachment.Attachment1.Name, attachment.Attachment1.Game),
            config.GetStringForGame(attachment.Attachment2?.Name, attachment.Attachment2?.Game),
            config.GetStringForGame(attachment.Attachment3?.Name, attachment.Attachment3?.Game)
        }.Where(attach => !string.IsNullOrWhiteSpace(attach)));

        return attachmentText;
    }

    var weapons = Model.ByWeapon
        .Where(hit => hit.DamageInflicted > 0 || (hit.DamageInflicted == 0 && hit.HitCount > 0))
        .GroupBy(hit => new { hit.WeaponId })
        .Select(group =>
        {
            var withoutAttachments = group.FirstOrDefault(hit => hit.WeaponAttachmentComboId == null);
            var mostUsedAttachment = group.Except(new[] { withoutAttachments })
                .OrderByDescending(g => g.DamageInflicted)
                .GroupBy(g => g.WeaponAttachmentComboId)
                .FirstOrDefault()
                ?.FirstOrDefault();

            if (withoutAttachments == null || mostUsedAttachment == null)
            {
                return withoutAttachments;
            }

            withoutAttachments.WeaponAttachmentComboId = mostUsedAttachment.WeaponAttachmentComboId;
            withoutAttachments.WeaponAttachmentCombo = mostUsedAttachment.WeaponAttachmentCombo;

            return withoutAttachments;
        })
        .Where(hit => hit != null)
        .OrderByDescending(hit => hit.KillCount)
        .ToList();

    var allPerServer = Model.All.Where(hit => hit.ServerId == Model.ServerId).ToList();

    // if the serverId is supplied we want all the entries with serverID but nothing else
    var aggregate = Model.ServerId == null
        ? Model.Aggregate
        : allPerServer.Where(hit => hit.WeaponId == null)
            .Where(hit => hit.HitLocation == null)
            .Where(hit => hit.ServerId == Model.ServerId)
            .Where(hit => hit.WeaponAttachmentComboId == null)
            .FirstOrDefault(hit => hit.MeansOfDeathId == null);

    var filteredHitLocations = Model.ByHitLocation
        .Where(hit => hit.HitCount > 0)
        .Where(hit => hit.HitLocation.Name != "none")
        .Where(hit => hit.HitLocation.Name != "neck")
        .Where(hit => hit.ServerId == Model.ServerId)
        .OrderByDescending(hit => hit.HitCount)
        .ThenBy(hit => hit.HitLocationId)
        .ToList();

    var uniqueWeapons = allPerServer.Any()
        ? Model.ByWeapon.Where(hit => hit.ServerId == Model.ServerId)
            .Where(weapon => weapon.DamageInflicted > 0)
            .GroupBy(weapon => weapon.WeaponId)
            .Count()
        : (int?)null; // want to default to -- in ui instead of 0

    var activeTime = weapons.Any()
        ? TimeSpan.FromSeconds(weapons.Sum(weapon => weapon.UsageSeconds ?? 0))
        : (TimeSpan?)null; // want to default to -- in ui instead of 0

    var kdr = aggregate == null
        ? null
        : Math.Round(aggregate.KillCount / (float)aggregate.DeathCount, 2).ToString(Utilities.CurrentLocalization.Culture);

    var serverLegacyStat = Model.LegacyStats
        .FirstOrDefault(stat => stat.ServerId == Model.ServerId);

    // legacy stats section
    var performance = Model.Performance;
    var skill = Model.ServerId != null ? serverLegacyStat?.Skill.ToNumericalString() : Model.LegacyStats.WeightValueByPlaytime(nameof(EFClientStatistics.Skill), 0).ToNumericalString();
    var elo = Model.ServerId != null ? serverLegacyStat?.EloRating.ToNumericalString() : Model.LegacyStats.WeightValueByPlaytime(nameof(EFClientStatistics.EloRating), 0).ToNumericalString();
    var spm = Model.ServerId != null ? serverLegacyStat?.SPM.ToNumericalString() : Model.LegacyStats.WeightValueByPlaytime(nameof(EFClientStatistics.SPM), 0).ToNumericalString();

    var performanceHistory = Model.Ratings
        .OrderBy(rating => rating.CreatedDateTime)
        .Select(rating => new PerformanceHistory { Performance = rating.PerformanceMetric, OccurredAt = rating.CreatedDateTime });

    if (performance != null && performance != Model.Ratings.FirstOrDefault().PerformanceMetric)
    {
        performanceHistory = performanceHistory.Append(new PerformanceHistory { Performance = performance.Value, OccurredAt = Model.Ratings.FirstOrDefault()?.CreatedDateTime ?? DateTime.UtcNow });
    }

    var score = allPerServer.Any()
        ? allPerServer.Sum(stat => stat.Score)
        : null;

    var headShots = allPerServer.Any()
        ? allPerServer.Where(hit => hit.MeansOfDeath?.Name == headshotKey || hit.HitLocation?.Name == headshotKey2).Sum(hit => hit.HitCount)
        : (int?)null; // want to default to -- in ui instead of 0

    var meleeKills = allPerServer.Any()
        ? allPerServer.Where(hit => hit.MeansOfDeath?.Name == meleeKey).Sum(hit => hit.KillCount)
        : (int?)null;

    var suicides = allPerServer.Any()
        ? allPerServer.Where(hit => suicideKeys.Contains(hit.MeansOfDeath?.Name ?? "")).Sum(hit => hit.KillCount)
        : (int?)null;

    var statCards = new[]
    {
        new
        {
            Name = (ViewBag.Localization["PLUGINS_STATS_TEXT_KILLS"] as string).Titleize(),
            Value = aggregate?.KillCount.ToNumericalString()
        },
        new
        {
            Name = (ViewBag.Localization["PLUGINS_STATS_TEXT_DEATHS"] as string).Titleize(),
            Value = aggregate?.DeathCount.ToNumericalString()
        },
        new
        {
            Name = (ViewBag.Localization["PLUGINS_STATS_TEXT_KDR"] as string).Titleize(),
            Value = kdr
        },
        new
        {
            Name = (ViewBag.Localization["WEBFRONT_ADV_STATS_SCORE"] as string).Titleize(),
            Value = score.ToNumericalString()
        },
        new
        {
            Name = (ViewBag.Localization["WEBFRONT_ADV_STATS_ZSCORE"] as string),
            Value = Model.ZScore.ToNumericalString(2)
        },
        new
        {
            Name = (ViewBag.Localization["PLUGINS_STATS_TEXT_SKILL"] as string).ToLower().Titleize(),
            Value = skill
        },
        new
        {
            Name = (ViewBag.Localization["WEBFRONT_ADV_STATS_ELO"] as string).Titleize(),
            Value = elo
        },
        new
        {
            Name = (ViewBag.Localization["PLUGINS_STATS_META_SPM"] as string).Titleize(),
            Value = spm
        },
        new
        {
            Name = ViewBag.Localization["WEBFRONT_ADV_STATS_TOTAL_DAMAGE"] as string,
            Value = aggregate?.DamageInflicted.ToNumericalString()
        },
        new
        {
            Name = ViewBag.Localization["WEBFRONT_ADV_STATS_SUICIDES"] as string,
            Value = suicides.ToNumericalString()
        },
        new
        {
            Name = ViewBag.Localization["WEBFRONT_ADV_STATS_HEADSHOTS"] as string,
            Value = headShots.ToNumericalString()
        },
        new
        {
            Name = ViewBag.Localization["WEBFRONT_ADV_STATS_MELEES"] as string,
            Value = meleeKills.ToNumericalString()
        },
        new
        {
            Name = ViewBag.Localization["WEBFRONT_ADV_STATS_FAV_WEAP"] as string,
            Value = GetWeaponNameForHit(weapons.FirstOrDefault())
        },
        new
        {
            Name = ViewBag.Localization["WEBFRONT_ADV_STATS_FAV_ATTACHMENTS"] as string,
            Value = GetWeaponAttachmentName(weapons.FirstOrDefault()?.WeaponAttachmentCombo)
        },
        new
        {
            Name = ViewBag.Localization["WEBFRONT_ADV_STATS_TOTAL_WEAPONS_USED"] as string,
            Value = uniqueWeapons.ToNumericalString()
        },
        new
        {
            Name = ViewBag.Localization["WEBFRONT_ADV_STATS_TOTAL_ACTIVE_TIME"] as string,
            Value = activeTime?.HumanizeForCurrentCulture()
        }
    };
}

<div class="content row mt-20">
    <!-- main content -->
    <div class="col-12 col-lg-9 mt-0">
        <h2 class="content-title mb-0">@ViewBag.Title</h2>
        <span class="text-muted">
            <color-code value="@(Model.Servers.FirstOrDefault(server => server.Endpoint == Model.ServerEndpoint)?.Name ?? ViewBag.Localization["WEBFRONT_STATS_INDEX_ALL_SERVERS"])"></color-code>
        </span>

        <!-- top card -->
        <div class="card p-20 m-0 mt-15 mb-15">
            <div class="align-self-center d-flex flex-column flex-lg-row flex-fill mb-15">
                <!-- rank icon -->
                <img class="img-fluid align-self-center w-75" id="rank_icon" src="~/images/stats/ranks/rank_@(Model.ZScore.RankIconIndexForZScore()).png" alt="@performance"/>
                <!-- summary -->
                <div class="d-flex flex-column align-self-center m-10 text-center text-lg-left" id="client_stats_summary">
                    <div class="font-size-20 mb-0 font-weight-bold">
                        <a asp-controller="Client" asp-action="Profile" asp-route-id="@Model.ClientId" class="no-decoration">@Model.ClientName.StripColors()</a>
                    </div>
                    @if (Model.Level == EFClient.Permission.Banned)
                    {
                        <div class="h5 mb-0 text-danger">@ViewBag.Localization["GLOBAL_PERMISSION_BANNED"]</div>
                    }
                    else if (Model.ZScore != null)
                    {
                        if (Model.Ranking > 0)
                        {
                            <div class="h5 mb-0">@Html.Raw((ViewBag.Localization["WEBFRONT_ADV_STATS_RANKED_V2"] as string).FormatExt(Model.Ranking?.ToString("#,##0"), Model.TotalRankedClients.ToString("#,##0")))</div>
                        }

                        else
                        {
                            <div class="h5 mb-0">@ViewBag.Localization["WEBFRONT_ADV_STATS_EXPIRED"]</div>
                        }

                        if (Model.ServerId != null)
                        {
                            <div class="h5 mb-0">@Html.Raw((ViewBag.Localization["WEBFRONT_ADV_STATS_PERFORMANCE"] as string).FormatExt($"<span class=\"text-primary\">{performance.ToNumericalString()}</span>"))</div>
                        }

                        else
                        {
                            <div class="h5 mb-0">@Html.Raw((ViewBag.Localization["WEBFRONT_ADV_STATS_RATING"] as string).FormatExt($"<span class=\"text-primary\">{Model.Rating.ToNumericalString()}</span>"))</div>
                        }
                    }

                    else
                    {
                        <div class="h5 mb-0">@ViewBag.Localization["WEBFRONT_STATS_INDEX_UNRANKED"]</div>
                    }
                </div>
                <!-- history graph -->
                @if (performanceHistory.Count() > 5)
                {
                    <div class="w-full w-lg-half m-auto ml-lg-auto" id="client_performance_history_container">
                        <canvas id="client_performance_history" data-history="@(JsonSerializer.Serialize(performanceHistory))"></canvas>
                    </div>
                }
            </div>
            <hr class="m-10"/>
            <div class="d-flex flex-row flex-wrap rounded">
                @foreach (var card in statCards)
                {
                    <div class="stat-card bg-very-dark-dm bg-light-ex-lm p-15 m-md-5 w-half w-md-200 rounded flex-fill">
                        @if (string.IsNullOrWhiteSpace(card.Value))
                        {
                            <div class="m-0">&mdash;</div>
                        }
                        else
                        {
                            <div class="m-0 font-size-16 text-primary">@card.Value</div>
                        }
                        <div class="font-size-12 text-muted">@card.Name</div>
                    </div>
                }
            </div>
        </div>

        <div class="d-flex flex-wrap flex-column-reverse flex-xl-row">
            <!-- hit locations -->
            @{
                var totalHits = filteredHitLocations.Sum(hit => hit.HitCount);

                var hitLocationsTable = new TableInfo(5)
                {
                    Header = ViewBag.Localization["WEBFRONT_ADV_STATS_HIT_LOCATIONS"]
                };

                hitLocationsTable.WithColumns(new string[]
                {
                    ViewBag.Localization["WEBFRONT_ADV_STATS_LOCATION"],
                    ViewBag.Localization["WEBFRONT_ADV_STATS_HITS"],
                    ViewBag.Localization["WEBFRONT_ADV_STATS_PERCENTAGE"],
                    ViewBag.Localization["WEBFRONT_ADV_STATS_DAMAGE"],
                }).WithRows(filteredHitLocations, hitLocation => new[]
                {
                    config.GetStringForGame(hitLocation.HitLocation.Name, hitLocation.HitLocation.Game),
                    hitLocation.HitCount.ToString(),
                    $"{Math.Round((hitLocation.HitCount / (float)totalHits) * 100.0).ToString(Utilities.CurrentLocalization.Culture)}%",
                    hitLocation.DamageInflicted.ToNumericalString()
                });
            }

            <div class="mr-0 mr-xl-20 flex-fill flex-xl-grow-1">
                <partial name="_DataTable" for="@hitLocationsTable"></partial>

                <div class="h-250 p-15 card m-0 d-flex justify-content-center rounded-bottom" id="hitlocation_container">
                    <canvas id="hitlocation_model">
                    </canvas>
                </div>
            </div>

            <!-- weapons used -->
            @{
                var weaponsUsedTable = new TableInfo(10)
                {
                    Header = ViewBag.Localization["WEBFRONT_ADV_STATS_WEAP_USAGE"]
                };

                weaponsUsedTable.WithColumns(new string[]
                {
                    ViewBag.Localization["WEBFRONT_ADV_STATS_WEAPON"],
                    ViewBag.Localization["WEBFRONT_ADV_STATS_FAV_ATTACHMENTS"],
                    ViewBag.Localization["WEBFRONT_ADV_STATS_KILLS"],
                    ViewBag.Localization["WEBFRONT_ADV_STATS_HITS"],
                    ViewBag.Localization["WEBFRONT_ADV_STATS_DAMAGE"],
                    ViewBag.Localization["WEBFRONT_ADV_STATS_USAGE"]
                }).WithRows(weapons, weapon => new[]
                {
                    GetWeaponNameForHit(weapon),
                    GetWeaponAttachmentName(weapon.WeaponAttachmentCombo) ?? "--",
                    weapon.KillCount.ToNumericalString(),
                    weapon.HitCount.ToNumericalString(),
                    weapon.DamageInflicted.ToNumericalString(),
                    TimeSpan.FromSeconds(weapon.UsageSeconds ?? 0).HumanizeForCurrentCulture(minUnit: TimeUnit.Second)
                });
            }

            <div class="flex-fill flex-xl-grow-1">
                <partial name="_DataTable" for="@weaponsUsedTable"/>
            </div>
        </div>
    </div>
    <!-- side context menu -->
    @{
        var menuItems = new SideContextMenuItems
        {
            MenuTitle = ViewBag.Localization["WEBFRONT_CONTEXT_MENU_GLOBAL_GAME"],
            Items = Model.Servers.Select(server => new SideContextMenuItem
            {
                IsLink = true,
                Reference = Url.Action("Advanced", "ClientStatistics", new { serverId = server.Endpoint }),
                Title = server.Name.StripColors(),
                IsActive = Model.ServerEndpoint == server.Endpoint,
                IsCollapse = true,
                Meta = server.Game.ToString()
            }).Prepend(new SideContextMenuItem
            {
                IsLink = true,
                Reference = Url.Action("Advanced", "ClientStatistics"),
                Title = ViewBag.Localization["WEBFRONT_STATS_INDEX_ALL_SERVERS"],
                IsActive = Model.ServerEndpoint is null
            }).ToList()
        };
    }
    <partial name="_SideContextMenu" for="@menuItems"></partial>
</div>


@{
    var projection = filteredHitLocations.Select(loc => new
    {
        name = loc.HitLocation.Name,
        // we want to count head and neck as the same
        percentage = (loc.HitLocation.Name == "head"
            ? filteredHitLocations.FirstOrDefault(c => c.HitLocation.Name == "neck")?.HitCount ?? 0 + loc.HitCount
            : loc.HitCount) / (float)totalHits
    }).ToList();
    var maxPercentage = projection.Any() ? projection.Max(p => p.percentage) : 0;
}

@section scripts
{
    <script type="text/javascript">
    const hitLocationData = @Html.Raw(Json.Serialize(projection));
    const maxPercentage = @maxPercentage;
    </script>

    <environment include="Development">
        <script type="text/javascript" src="~/js/advanced_stats.js"></script>
    </environment>
}
