@using LANCommander.Components.FileManagerComponents;
@using LANCommander.Data.Enums;
@using LANCommander.Extensions;
@using LANCommander.Models
@using LANCommander.Services
@using System.IO.Compression;
@inject ScriptService ScriptService
@inject ModalService ModalService
@inject IMessageService MessageService

@{
    RenderFragment Footer =
    @<Template>
        <Button OnClick="Save" Disabled="@(String.IsNullOrWhiteSpace(Script.Name))" Type="@ButtonType.Primary">Save</Button>
        <Button OnClick="Close">Close</Button>
    </Template>;
}

<Modal Visible="ModalVisible" Footer="@Footer" Title="@(Script == null ? "Add Script" : "Edit Script")" OkText="@("Save")" Maximizable="false" DefaultMaximized="true" Closable="true" OnCancel="Close">
    <Form Model="@Script" Layout="@FormLayout.Vertical">
        <FormItem>
            @foreach (var group in Snippets.Select(s => s.Group).Distinct())
            {
                <Dropdown>
                    <Overlay>
                        <Menu>
                            @foreach (var snippet in Snippets.Where(s => s.Group == group))
                            {
                                <MenuItem OnClick="() => InsertSnippet(snippet)">
                                    @snippet.Name
                                </MenuItem>
                            }
                        </Menu>
                    </Overlay>

                    <ChildContent>
                        <Button Type="@ButtonType.Primary">@group</Button>
                    </ChildContent>
                </Dropdown>
            }

            @if (ArchiveId != Guid.Empty)
            {
                <Button Icon="@IconType.Outline.FolderOpen" OnClick="BrowseForPath" Type="@ButtonType.Text">Browse</Button>
            }

            <Button Icon="@IconType.Outline.Build" OnClick="() => RegToPowerShell.Open()" Type="@ButtonType.Text">Import .reg</Button>
        </FormItem>

        <FormItem>
            <StandaloneCodeEditor @ref="Editor" Id="editor" ConstructionOptions="EditorConstructionOptions" />
        </FormItem>

        <FormItem Label="Name">
            <Input @bind-Value="@context.Name" />
        </FormItem>

        <FormItem Label="Type">
            <Select @bind-Value="context.Type" TItem="ScriptType" TItemValue="ScriptType" DataSource="Enum.GetValues<ScriptType>().Where(st => AllowedTypes == null || AllowedTypes.Contains(st))">
                <LabelTemplate Context="Value">@Value.GetDisplayName()</LabelTemplate>
                <ItemTemplate Context="Value">@Value.GetDisplayName()</ItemTemplate>
            </Select>
        </FormItem>

        <FormItem>
            <Checkbox @bind-Checked="context.RequiresAdmin">Requires Admin</Checkbox>
        </FormItem>

        <FormItem Label="Description">
            <TextArea @bind-Value="context.Description" MaxLength=500 ShowCount />
        </FormItem>
    </Form>
</Modal>

<RegToPowerShell @ref="RegToPowerShell" OnParsed="(text) => InsertText(text)" />

<Space Direction="DirectionVHType.Vertical" Size="@("large")" Style="width: 100%">
    <SpaceItem>
        <Table TItem="Script" DataSource="@Scripts" HidePagination="true" Responsive>
            <PropertyColumn Property="s => s.Type">@context.Type.GetDisplayName()</PropertyColumn>
            <PropertyColumn Property="s => s.CreatedBy">
                @context.CreatedBy?.UserName
            </PropertyColumn>
            <PropertyColumn Property="s => s.CreatedOn" Format="MM/dd/yyyy hh:mm tt" />
            <ActionColumn Title="">
                <Space Style="display: flex; justify-content: end">
                    <SpaceItem>
                        <Button OnClick="() => Edit(context)" Icon="@IconType.Outline.Edit" Type="@ButtonType.Text" />

                        <Popconfirm OnConfirm="() => Delete(context)" Title="Are you sure you want to delete this script?">
                            <Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger />
                        </Popconfirm>
                    </SpaceItem>
                </Space>
            </ActionColumn>
        </Table>
    </SpaceItem>

    <SpaceItem>
        <GridRow Justify="end">
            <GridCol>
                <Button OnClick="() => Edit()" Type="@ButtonType.Primary">Add Script</Button>
            </GridCol>
        </GridRow>
    </SpaceItem>
</Space>

<style>
    .monaco-editor-container {
        height: 600px;
    }
</style>

 @code {
    [Parameter] public Guid GameId { get; set; }
    [Parameter] public Guid RedistributableId { get; set; }
    [Parameter] public Guid ArchiveId { get; set; }
    [Parameter] public ICollection<Script> Scripts { get; set; }
    [Parameter] public EventCallback<ICollection<Script>> ScriptsChanged { get; set; }
    [Parameter] public IEnumerable<ScriptType> AllowedTypes { get; set; }

    Script Script;

    bool ModalVisible = false;

    IEnumerable<Snippet> Snippets { get; set; }
    StandaloneCodeEditor? Editor;
    RegToPowerShell RegToPowerShell;

    private StandaloneEditorConstructionOptions EditorConstructionOptions(StandaloneCodeEditor editor)
    {
        return new StandaloneEditorConstructionOptions
        {
            AutomaticLayout = true,
            Language = "powershell",
            Value = Script.Contents,
            Theme = "vs-dark",
        };
    }

    protected override async Task OnInitializedAsync()
    {
        if (Scripts == null)
            Scripts = new List<Script>();

        Snippets = ScriptService.GetSnippets();

        if (Script == null)
            Script = new Script();
    }

    private async void Edit(Script script = null)
    {
        if (script == null) {
            if (GameId != Guid.Empty)
                Script = new Script() { GameId = GameId };

            if (RedistributableId != Guid.Empty)
                Script = new Script() { RedistributableId = RedistributableId };

            if (Editor != null)
                await Editor.SetValue("");
        }
        else
            Script = script;

        if (Editor != null && Script != null)
            await Editor.SetValue(Script.Contents);

        ModalVisible = true;

        StateHasChanged();
    }

    private async void Delete(Script script = null)
    {
        if (script != null)
            await ScriptService.Delete(script);

        await MessageService.Success("Script deleted!");
    }

    private void Close()
    {
        ModalVisible = false;
    }

    private async Task Save()
    {
        var value = await Editor.GetValue();

        Script.Contents = value;

        if (Script.Id == Guid.Empty)
            Script = await ScriptService.Add(Script);
        else
            Script = await ScriptService.Update(Script);

        Close();

        StateHasChanged();

        await MessageService.Success("Script saved!");
    }

    private async Task InsertText(string text)
    {
        var line = await Editor.GetPosition();
        var range = new BlazorMonaco.Range(line.LineNumber, 1, line.LineNumber, 1);

        var currentSelections = await Editor.GetSelections();

        await Editor.ExecuteEdits("ScriptEditor", new List<IdentifiedSingleEditOperation>()
        {
            new IdentifiedSingleEditOperation
            {
                Range = range,
                Text = text,
                ForceMoveMarkers = true
            }
        }, currentSelections);
    }

    private async Task InsertSnippet(Snippet snippet)
    {
        await InsertText(snippet.Content);
    }

    private async void BrowseForPath()
    {
        var modalOptions = new ModalOptions()
        {
            Title = "Choose Reference",
            Maximizable = false,
            DefaultMaximized = true,
            Closable = true,
            OkText = "Insert File Path"
        };

        var browserOptions = new FilePickerOptions()
        {
            ArchiveId = ArchiveId,
            Select = true,
            Multiple = false
        };

        var modalRef = await ModalService.CreateModalAsync<FilePickerDialog, FilePickerOptions, IEnumerable<IFileManagerEntry>>(modalOptions, browserOptions);

        modalRef.OnOk = (results) =>
        {
            var path = results.FirstOrDefault().Path;

            InsertText($"$InstallDir\\{path.Replace('/', '\\')}");

            StateHasChanged();
            return Task.CompletedTask;
        };
    }
}
