@page "/teams/assignment"
@attribute [Authorize]
@using Core.Calculation
@using Microsoft.EntityFrameworkCore
@using WebApp.Models
@using EventAssignment = Core.Calculation.EventAssignment
@inject AppDbContext Context
@inject IDialogService DialogService
@inject NavigationManager NavigationManager

<PageTitle>Event Assignment - TSA Chapter Organizer</PageTitle>

<MudText Typo="Typo.h3">Assignment</MudText>

<MudGrid>
    <MudItem><MudText>Optimized team assignments based on the student event rankings</MudText></MudItem>
    <MudItem><MudButton StartIcon="@Icons.Material.Filled.Edit" Href="students/event-ranking">Edit Student Event Rankings</MudButton></MudItem>
</MudGrid>

<MudPaper Class="pa-4 mt-5">
    <MudGrid>
        <MudItem Style="width:160px;">
            <MudNumericField @bind-Value="_parameters.TeamSizeLimit"
                             Label="Team Size Limit" Min="3" Max="8"></MudNumericField>
        </MudItem>
        <MudItem>
            <MudTooltip Text="Require at least one On-Site Event">
                <MudSwitch @bind-Value="_parameters.RequireOnSite" Color="Color.Info"
                           Label="On-Site" />
            </MudTooltip>
        </MudItem>
        <MudItem>
            <MudTooltip Text="Require at least one Regional Event">
                <MudSwitch @bind-Value="_parameters.RequireRegional" Color="Color.Info"
                           Label="Regional" />
            </MudTooltip>
        </MudItem>
        <MudItem>
            <MudStack Style="width:100px;">
                <MudTooltip Text="Student Event Count Assignment Range">
                    <MudInputLabel>Event Count</MudInputLabel>
                </MudTooltip>
                <MudNumericField @bind-Value="_parameters.EventsLowerBound"
                                 Label="At Least" Min="2" Max="4"></MudNumericField>

                <MudNumericField @bind-Value="_parameters.EventsUpperBound"
                                 Label="Up to" Min="3" Max="5"></MudNumericField>
            </MudStack>
        </MudItem>
        <MudItem>
            <MudStack Style="width:100px;">
                <MudTooltip Text="Student Level of Effort Range">
                    <MudInputLabel>LOE</MudInputLabel>
                </MudTooltip>
                <MudNumericField @bind-Value="_parameters.EffortLowerBound"
                                 Label="At Least" Min="4" Max="7"></MudNumericField>

                <MudNumericField @bind-Value="_parameters.EffortUpperBound"
                                 Label="Up to" Min="7" Max="12"></MudNumericField>
            </MudStack>
        </MudItem>
        <MudItem>
            <MudInputLabel>Assignment Requirements</MudInputLabel>
            <MudTable T="AssignmentRequirement" ServerData="ReloadAssignmentRequirements" @ref="_assignmentRequirementData">
               
                <RowTemplate Context="item">
                    <MudTd Class="align-center">
                        <MudIconButton Icon="@Icons.Material.Filled.RemoveCircle" Size="Size.Small"
                                       OnClick="() => RemoveRequireEvent(item)"></MudIconButton>
                    </MudTd>
                    <MudTd Class="align-center">
                        @item.Student.FirstName
                        @item.EventDefinition.ShortName
                        @if (item.Requirement == Requirement.Include)
                        {
                            <MudIcon Class="ml-3" Icon="@Icons.Material.Filled.ThumbUp" Size="Size.Small"></MudIcon>
                        }
                        @if (item.Requirement == Requirement.Exclude)
                        {
                            <MudIcon Class="ml-3" Icon="@Icons.Material.Filled.ThumbDownAlt" Size="Size.Small"></MudIcon>
                        }
                    </MudTd>
                </RowTemplate>
            </MudTable>
        </MudItem>
        <MudItem>
            <MudInputLabel>Two Team Events</MudInputLabel>
            <MudTable T="EventDefinition" ServerData="ReloadEventTwoTeam" @ref="_eventTwoTeamData">
                
                <RowTemplate Context="item">
                    <MudTd Class="align-center">
                        <MudIconButton Icon="@Icons.Material.Filled.RemoveCircle" Size="Size.Small"
                                       OnClick="() => RemoveTwoTeam(item)"></MudIconButton>
                    </MudTd>
                    <MudTd Class="align-center">@item.ShortName</MudTd>
                </RowTemplate>
            </MudTable>
        </MudItem>
        <MudItem>
            <MudInputLabel>Omitted Events</MudInputLabel>
            <MudTable T="EventDefinition" ServerData="ReloadOmittedEvents" @ref="_eventOmittedData">
               
                <RowTemplate Context="item">
                    <MudTd Class="align-center">
                        <MudIconButton Icon="@Icons.Material.Filled.RemoveCircle" Size="Size.Small"
                                       OnClick="() => RemoveOmitted(item)"></MudIconButton>
                    </MudTd>
                    <MudTd Class="align-center">@item.ShortName</MudTd>
                </RowTemplate>
            </MudTable>
        </MudItem>
    </MudGrid>
    <MudButton Class="ma-3" OnClick="Solve" Variant="Variant.Filled" Color="Color.Primary" Disabled="@_isSolving">Solve</MudButton>
</MudPaper>

<MudGrid>
    <MudItem xs="12" lg="8">
        <MudText Typo="Typo.h4">Students</MudText>

        <MudTable T="StudentEventStatistics" ServerData="ReloadStatistics" @ref="_statisticData" >
            <ColGroup>
                <col style="width: 150px;" />
                <col style="width: 50px;" />
                <col style="width: 50px;" />
                <col style="width: 60px;" />
            </ColGroup>
            <HeaderContent>
                <MudTh>Student</MudTh>
                <MudTh><MudTooltip Text="How many events they're assigned'">Event Count</MudTooltip></MudTh>
                <MudTh><MudTooltip Text="Level of Effort Total">LOE Sum</MudTooltip></MudTh>
                <MudTh><MudTooltip Text="Assignment Warnings">Warnings</MudTooltip></MudTh>
            </HeaderContent>
            <RowTemplate>
                <MudTd><b>@context.Student.FirstName</b></MudTd>
                <MudTd>@context.EventCount</MudTd>
                <MudTd>@context.TotalLevelOfEffort</MudTd>
                <MudTd>@if (!context.HasOnSiteActivity)
                       {
                           <MudTooltip Text="No On-Site Activity">
                            <MudText Style="font-weight:bolder" Color="Color.Warning">@AppIcons.OnSiteActivity</MudText>
                           </MudTooltip>
                       }
                    @if (!context.HasRegionalEvent)
                    {
                        <MudTooltip Text="No Regional Event">
                            <MudText Style="font-weight:bolder" Color="Color.Warning">@AppIcons.RegionalEvent</MudText>
                        </MudTooltip>
                    }
                </MudTd>
            </RowTemplate>
            <ChildRowContent>
                <MudTr><td colspan="4">
                    @{
                        var allStudentEvents =
                            context.Student.EventRankings
                                .OrderBy(e => e.Rank)
                                .Select(e => e.EventDefinition)
                                .Concat(context.Events)
                                .Distinct();
                    }
                    @foreach (var e in
                              allStudentEvents
                                  .OrderBy(e =>
                                      context.Student.EventRankings
                                          .Find(ser => ser.EventDefinition == e)?.Rank ?? 10))
                    {
                        var eventRank = context.Student.EventRankings.Find(er => er.EventDefinition == e)?.Rank;
                        var isAssigned = context.Events.Contains(e);

                        var color = AppIcons.RankedEventColor(eventRank ?? 0);
                        var style = string.Empty;

                        if (isAssigned)
                        {
                            style += "border-color:black; border-width:thin;";
                            if (eventRank.HasValue)
                            {
                                style += $"background:{color};";
                                if (eventRank == 1)
                                    style += $"color:black";
                            }
                            else
                                style += $"background:{Colors.Gray.Lighten3};";
                        }
                        else
                        {
                            if (eventRank.HasValue)
                                style += $"border-color:{color}; border-width:medium; color:{Colors.Gray.Lighten1};";
                        }

                        <MudPaper Class="d-inline-flex align-center pa-2 mx-3 my-1 border-solid" Style="@(style)">
                            @e.ShortName&nbsp;
                            @AppIcons.EventAttributes(e)
                            @{
                                var isIncluded = _assignmentRequirements
                                    .Find(ar =>
                                        ar.EventDefinition == e
                                        && ar.Student == context.Student
                                        && ar.Requirement == Requirement.Include) == null;
                                var isExcluded = _assignmentRequirements
                                    .Find(ar =>
                                        ar.EventDefinition == e
                                        && ar.Student == context.Student
                                        && ar.Requirement == Requirement.Exclude) == null;
                            }
                            @if (isIncluded)
                            {
                                <MudTooltip Title="@($"Add requirement for {context.Student.FirstName} in {e.ShortName}")">
                                    <MudIconButton Icon="@Icons.Material.Outlined.ThumbUpAlt" Class="ml-3" Size="Size.Small" Color="Color.Default"
                                                   OnClick="() => RequireEvent(e, context.Student, Requirement.Include)"></MudIconButton>
                                </MudTooltip>
                            }
                            else
                            {
                                <MudTooltip Title="@($"Remove requirement for {context.Student.FirstName} in {e.ShortName}")">
                                    <MudIconButton Icon="@Icons.Material.Filled.ThumbUpAlt" Class="ml-3" Size="Size.Small" Color="Color.Dark"
                                                   OnClick="() => RemoveRequireEvent(e, context.Student, Requirement.Include)"></MudIconButton>
                                </MudTooltip>
                            }

                            @if (isExcluded)
                            {
                                <MudTooltip Title="@($"Add restriction against {context.Student.FirstName} in {e.ShortName}")">
                                    <MudIconButton Icon="@Icons.Material.Outlined.ThumbDownAlt" Size="Size.Small" Color="Color.Default"
                                                   OnClick="() => RequireEvent(e, context.Student, Requirement.Exclude)"></MudIconButton>
                                </MudTooltip>
                            }
                            else
                            {
                                <MudTooltip Title="@($"Remove restriction against {context.Student.FirstName} in {e.ShortName}")">
                                    <MudIconButton Icon="@Icons.Material.Filled.ThumbDownAlt" Size="Size.Small" Color="Color.Dark"
                                                   OnClick="() => RemoveRequireEvent(e, context.Student, Requirement.Exclude)"></MudIconButton>
                                </MudTooltip>
                            }
                        </MudPaper>
                    }
                    <MudDivider Style="border-width:3px" />
                </td></MudTr>
            </ChildRowContent>
        </MudTable>
    </MudItem>
    <MudItem xs="12" lg="4">
        <MudText Typo="Typo.h4">Teams</MudText>
        <MudTable T="Team" ServerData="SolveAssignments" @ref="_teamData">
            <ColGroup>
                <col style="width: 200px;" />
                <col style="width: 40px; white-space:nowrap" />
            </ColGroup>
            <HeaderContent>
                <MudTh>Team</MudTh>
                <MudTh><MudTooltip Text="Number of Student Rankings, Number of TimeSlots [Eligibility Lower Bound-Upper Bound]"><MudText Style="white-space:nowrap;">R, # [LB-UB]</MudText> </MudTooltip></MudTh>
            </HeaderContent>
            <RowTemplate>
                @{
                    var thresholds = _eventAssignmentThresholds.First(e => e.Event == context.Event);
                }
                <MudTd>
                    <b>@context.Event.Name</b>&nbsp;
                    <EventAttributes EventDefinition="context.Event"></EventAttributes>
                </MudTd>
                <MudTd Style="white-space:nowrap">
                
                    @thresholds.StudentRankingCount, [@thresholds.LowerBound-@thresholds.UpperBound] &times; @thresholds.TeamCount
                    
                    @if (_eventTwoTeams.Contains(context.Event))
                    {
                        <MudIconButton Class="ml-3" Size="Size.Small" Color="Color.Default"
                                       Icon="@Icons.Material.Filled.PlusOne" Variant="Variant.Filled"
                                       OnClick="() => RemoveTwoTeam(context.Event)"></MudIconButton>
                    }
                    else if (thresholds.TeamCount != 2 && context.Event.EventFormat == EventFormat.Team)
                    {
                        <MudIconButton Class="ml-3" Size="Size.Small" Color="Color.Default"
                                       Icon="@Icons.Material.Filled.PlusOne"
                                       OnClick="() => AddTwoTeam(context.Event)"></MudIconButton>
                    }
                    <MudIconButton Icon="@Icons.Material.Outlined.Remove" Size="Size.Small" Color="Color.Default"
                                   OnClick="() => AddOmitted(context.Event)"></MudIconButton>
                </MudTd>

            </RowTemplate>
            <ChildRowContent>
                <MudTr>
                    <td colspan="2">
                        <TeamStudents Team="@context"></TeamStudents>
                        <MudDivider Style="border-width:3px"/>
                    </td>
                </MudTr>
            </ChildRowContent>
            <NoRecordsContent>
                <MudText Color="Color.Warning">Solution status: @_solutionStatus</MudText>
            </NoRecordsContent>
            <LoadingContent>
                <MudText>Loading...</MudText>
            </LoadingContent>
        </MudTable>
    </MudItem>
</MudGrid>

<MudTooltip Text="This will overwrite existing teams">
<MudButton Class="ma-3" StartIcon="@Icons.Material.Filled.Warning" Variant="Variant.Filled" Size="Size.Large" OnClick="SaveTeams" Color="Color.Warning">Save</MudButton>
</MudTooltip>
@code {
    public bool TestSwitch { get; set; } = false;

    private readonly AssignmentParameters _parameters = new() { RequireOnSite = false, RequireRegional = false };

    private List<EventDefinition>? _events;
    private List<Student>? _students;
    private List<EventAssignmentThresholds> _eventAssignmentThresholds = [];

    MudTable<Team> _teamData;
    private Team[] _teams = [];
    MudTable<StudentEventStatistics> _statisticData;
    private List<StudentEventStatistics> _statistics = [];
    MudTable<AssignmentRequirement> _assignmentRequirementData;
    private List<AssignmentRequirement> _assignmentRequirements = [];
    MudTable<EventDefinition> _eventTwoTeamData;
    private List<EventDefinition> _eventTwoTeams = [];
    MudTable<EventDefinition> _eventOmittedData;
    private List<EventDefinition> _eventOmitted = [];

    private string _solutionStatus = string.Empty;

    private bool _isSolving = false;

    protected override async Task OnInitializedAsync()
    {
        _events =
            await Context.Events
                .OrderBy(e => e.Name)
                .ToListAsync();
        _students = 
            await Context.Students
                .Where(e => e.FirstName != "test")
                .Include(e => e.EventRankings)
                .ThenInclude(e => e.EventDefinition)
                .Where(e => e.EventRankings.Any())
                .OrderBy(e => e.FirstName).ToListAsync();
    }

    private async Task AddTeam()
    {
        //Context.TimeSlots.Add(Team);
        await Context.SaveChangesAsync();
        //NavigationManager.NavigateTo("/teams");
    }

    private void Solve()
    {
        _teamData.ReloadServerData();
    }

    private async Task<TableData<Team>> SolveAssignments(TableState arg1, CancellationToken arg2)
    {
        _isSolving = true;
        var eventAssignment = new EventAssignment(_events, _students, _parameters);
        foreach (var requirement in _assignmentRequirements)
        {
            eventAssignment.AddAssignmentRequirement(requirement);
        }
        eventAssignment.RemoveEvents(_eventOmitted);

        eventAssignment.AllowTwoTeams(_eventTwoTeams);

        var solution = await eventAssignment.Solve();
        _solutionStatus = solution.Status;
        _statistics =
            StudentEventStatistics.Generate(solution.Teams)
                .OrderByDescending(s => s.Student.Grade + s.Student.TsaYear)
                .ThenBy(s => s.Student.FirstName).ToList();
        _eventAssignmentThresholds = solution.AssignmentThresholds;
        await _statisticData.ReloadServerData();
        _isSolving = false;
        await InvokeAsync(StateHasChanged); // let the UI know that the solution has been found
        _teams = solution.Teams;

        return new TableData<Team> { Items = _teams };
    }

    private async Task<TableData<StudentEventStatistics>> ReloadStatistics(TableState arg1, CancellationToken arg2)
    {
        return new TableData<StudentEventStatistics> {Items = _statistics};
    }

    private async Task<TableData<AssignmentRequirement>> ReloadAssignmentRequirements(TableState arg1, CancellationToken arg2)
    {
        return new TableData<AssignmentRequirement> { Items = _assignmentRequirements };
    }

    private async Task<TableData<EventDefinition>> ReloadEventTwoTeam(TableState arg1, CancellationToken arg2)
    {
        return new TableData<EventDefinition> { Items = _eventTwoTeams };
    }


    private async Task<TableData<EventDefinition>> ReloadOmittedEvents(TableState arg1, CancellationToken arg2)
    {
        return new TableData<EventDefinition> { Items = _eventOmitted };
    }

    private void RequireEvent(EventDefinition evt, Student student, Requirement requirement)
    {
        _assignmentRequirements.Add(new AssignmentRequirement(evt, student, requirement));
        _assignmentRequirementData.ReloadServerData();
    }

    private void RemoveRequireEvent(EventDefinition evt, Student student, Requirement requirement)
    {
        var assignmentRequirement = 
            _assignmentRequirements
                .Find(ar => ar.EventDefinition == evt && ar.Student == student && ar.Requirement == requirement);
        if (assignmentRequirement != null) RemoveRequireEvent(assignmentRequirement);
    }

    private void RemoveRequireEvent(AssignmentRequirement assignmentRequirement)
    {
        _assignmentRequirements.Remove(assignmentRequirement);
        _assignmentRequirementData.ReloadServerData();
    }

    private void AddTwoTeam(EventDefinition evt)
    {
        _eventTwoTeams.Add(evt);
        _eventTwoTeamData.ReloadServerData();
    }

    private void RemoveTwoTeam(EventDefinition evt)
    {
        _eventTwoTeams.Remove(evt);
        _eventTwoTeamData.ReloadServerData();
    }


    private void AddOmitted(EventDefinition evt)
    {
        _eventOmitted.Add(evt);
        _eventOmittedData.ReloadServerData();
    }

    private void RemoveOmitted(EventDefinition evt)
    {
        _eventOmitted.Remove(evt);
        _eventOmittedData.ReloadServerData();
    }

    public async Task SaveTeams()
    {
        var result = await DialogService
            .ShowMessageBox("Save Teams",
                (MarkupString)$"Are you sure want to save these teams? Current teams will be erased. This cannot be undone.",
                yesText: "Yes",
                noText: "Cancel");

        if (result == true)
        {
            await Context.Teams.ExecuteDeleteAsync();
            await Context.Teams.AddRangeAsync(_teams);
            await Context.SaveChangesAsync();

            NavigationManager.NavigateTo("/teams");
        }
    }
}