@page "/docedit"
@page "/docedit/{docID:int}"
@using System.Reflection;
@using HyperCube.Models;
@inject NavigationManager NavigationManager;
@inject IJSRuntime JsRuntime;
@attribute [Authorize]
@*@attribute [Authorize(Roles = "admin")]*@

@inject AuthenticationStateProvider AuthenticationStateProvider
@using Microsoft.AspNetCore.Identity;
@inject UserManager<IdentityUser> UserManager;

<EditForm Model="@articleModel" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <h1>@header</h1>
    <br>
    <div style="width: 50%;">
        @if (docID < 1)
        {
            <p><InputFile id="inputDefault" OnChange="@HandleSelection" accept="application/pdf" /></p>
            //accept="application/pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document"
        }
        else
        {
            <p>Исходный документ: <a href=@FOLDER_NAME download="@articleModel.Filename" target="_top">@articleModel.Filename</a></p>
        }
        <p><InputText id="article_name" class="form-control" @bind-Value="articleModel.Name" placeholder="Наименование статьи" /></p>
        <p><InputDate id="date_publish" class="form-control" @bind-Value="articleModel.PublishDate" placeholder="Дата издания" /></p>
        <p><InputText id="author" class="form-control" @bind-Value="articleModel.Authors" placeholder="Автор" /></p>
        <p><InputTextArea id="keywords" class="form-control" @bind-Value="articleModel.Keywords" placeholder="Ключевые слова" /></p>
        <p><InputTextArea rows="5" id="annotation" class="form-control" @bind-Value="articleModel.Annotation" placeholder="Аннотация" /></p>
        <p><InputTextArea rows="10" id="text" class="form-control" @bind-Value="articleModel.Text" placeholder="Текст" /></p>

        @if (docID < 1)
        {
            <p><button class="btn btn-primary" type="submit">Загрузить</button></p>
        }
        else
        {
            @*<p>
                <InputRadioGroup @bind-Value="articleModel.Status">
                    Оценка:
                    <br>
                    @foreach (var status in (ArticleStatus[])Enum.GetValues(typeof(ArticleStatus)))
                        {
                        <InputRadio Value="status" />
                        @status
                        <br />
                        }
                </InputRadioGroup>
            </p>*@
            <p>
                <InputRadioGroup @bind-Value="articleModel.Rating">
                    Оценка:
                    <br>
                    @for (int i = 1; i < 6; i++)
                    {
                        <InputRadio Value="i" />
                        @i
                        <br />
                        }
                </InputRadioGroup>
            </p>
            <p>
                <button class="btn btn-danger" type="button" @onclick="@Cancel">Отклонить</button>
                <button @onclick="Verify" class="btn btn-primary" type="submit">Утвердить</button>
            </p>
        }
        <p>Статус: @status</p>
    </div>
</EditForm>

@code {
    [Parameter]
    public int docID { get; set; }

    const string FOLDER_NAME = "articles_storage";
    const long MAX_FILE_SIZE = 5120000; //bytes
    //const int ACC_ID = 1; //temp

    ArticleModel oldArticleModel = new();
    ArticleModel articleModel = new();
    AccountModel currentAcc = new();
    string status;
    string header;
    string storageFolderPath;
    MemoryStream memoryStream;

    async Task Verify()
    {
        try
        {
            VerifyContract verifyContract = SmartContract.Find("Verify") as VerifyContract;
            if (verifyContract != null)
            {
                await verifyContract.Run(articleModel);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    protected override async Task OnInitializedAsync()
    {
        currentAcc = await GetCurrentAcc();

        string path = AppDomain.CurrentDomain.BaseDirectory;
        storageFolderPath = (Path.Combine(path, FOLDER_NAME));

        if (docID > 0)
        {
            header = "Проверка материала";

            MySQLConnector dbCon = MySQLConnector.Instance();

            string stringSQL = $"SELECT articles.id, filename, article_name, authors, date_publish, annotation, keywords, action_type, rating " +
                $"FROM articles " +
                $"JOIN actions_history ON actions_history.article_id = articles.id " +
                $"WHERE articles.id={docID} " +
                $"ORDER BY actions_history.id DESC LiMIT 1";
            oldArticleModel = await dbCon.SQLSelectArticle(stringSQL);
            articleModel = (ArticleModel)oldArticleModel.Clone();

            string initiator = await articleModel.GetInitiatorUUID();
            status = $"Article ID={docID} loaded, status: {articleModel.Status}, initiatorUUID: {await articleModel.GetInitiatorUUID()}";
        }
        else
            header = "Загрузка материала";


        InitializeAccount();

        //int count = await articleModel.GetEditsCount();
        //int countbyid = await articleModel.GetEditsCount(currentAcc.UUID);
        //header += $", uuid:{currentAcc.UUID}, name: {currentAcc.Name}, edits count:{count}, count by accid: {countbyid}";
    }

    private async void HandleValidSubmit()
    {
        MySQLConnector dbCon = MySQLConnector.Instance();
        long id = 0;
        string stringSQL;

        if (docID > 0)
        {
            id = docID;
            stringSQL = $"UPDATE articles " +
                $"SET filename='{articleModel.Filename}', article_name='{articleModel.Name}', authors='{articleModel.Authors}', " +
                    $"date_publish='{articleModel.PublishDate.ToString("yyyy-MM-dd")}', annotation='{articleModel.Annotation}', " +
                    $"keywords='{articleModel.Keywords}', rating={articleModel.Rating} " +
                $"WHERE id={docID}";
            dbCon.SQLInsert(stringSQL);
        }
        else
        {
            stringSQL = $"INSERT INTO articles (filename, article_name, authors, date_publish, annotation, keywords) " +
                $"VALUES ('{articleModel.Filename}', '{articleModel.Name}', '{articleModel.Authors}', '{articleModel.PublishDate.ToString("yyyy-MM-dd")}'," +
                $"'{articleModel.Annotation}', '{articleModel.Keywords}')";
            id = dbCon.SQLInsert(stringSQL);
        }

        ///temp
        int action_type = docID > 0 ? 2 : 1;

        stringSQL = $"INSERT INTO actions_history (article_id, action_type, acc_id) " +
            $"VALUES ('{id}', '{action_type}', '{currentAcc.UUID}')";
        dbCon.SQLInsert(stringSQL);

        Dictionary<string, PropertyInfo> propDict = Compare.SimpleCompare<ArticleModel>(articleModel, oldArticleModel);
        foreach (KeyValuePair<string, PropertyInfo> prop in propDict)
        {
            //Console.WriteLine($"property name: {prop.Key}, value: {prop.Value.GetValue(articleModel, null)}");

            stringSQL = $"INSERT INTO articles_edit_log (article_id, acc_id, field_name, field_prevvalue, field_newvalue) " +
                $"VALUES ('{id}', '{currentAcc.UUID}', '{prop.Key}', '{prop.Value.GetValue(oldArticleModel, null)}', '{prop.Value.GetValue(articleModel, null)}')";
            dbCon.SQLInsert(stringSQL);
        }

        dbCon.Close();

        if (docID > 0)
        {
            status = propDict.Count > 0 ? "All changes saved, article has veryfied." : "Article verifyed without any changes.";
        }
        else
        {
            string fullpath = Path.Combine(storageFolderPath, $"{id}_{articleModel.Filename}");
            Directory.CreateDirectory(storageFolderPath);
            FileStream fs = new(fullpath, FileMode.Create, FileAccess.Write);
            memoryStream.Position = 0;
            await memoryStream.CopyToAsync(fs);

            Console.WriteLine($"User has saved new article data, {id}_{articleModel.Filename}, memory size:{memoryStream.Length}b, file size: {fs.Length}b");
            memoryStream.Close();
            fs.Close();

            status = "New article data saved.";

            bool confirmed = await JsRuntime.InvokeAsync<bool>("confirm", "Хотите загрузить еще статью?");
            if (confirmed)
                NavigationManager.NavigateTo("docedit", true);
            else
                NavigationManager.NavigateTo("");
        }
    }

    private async Task HandleSelection(InputFileChangeEventArgs e)
    {
        IBrowserFile file = e.File;
        if (file != null)
        {
            Stream stream = file.OpenReadStream(MAX_FILE_SIZE);
            memoryStream = new();
            await stream.CopyToAsync(memoryStream);
            status = $"Finished loading {memoryStream.Length} bytes from {file.Name}";

            DocParse docParse = new DocParse();
            oldArticleModel = DocParse.ReadPDF(memoryStream);
            oldArticleModel.Filename = file.Name;
            articleModel = (ArticleModel)oldArticleModel.Clone();
        }
    }

    private async void Cancel()
    {
        bool confirmed = await JsRuntime.InvokeAsync<bool>("confirm", "Вы уверены, что хотите отклонить статью?");
        if (confirmed)
        {
            ///какая-то логика отмены...
            NavigationManager.NavigateTo("");
        }
    }

    public async void InitializeAccount()
    {
        AccountModel.Current = await GetCurrentAcc();
        Console.WriteLine("InitializeAccount in DocEdit "+ AccountModel.Current.Name);
    }

    private async Task<AccountModel> GetCurrentAcc()
    {
        AccountModel account = new();

        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            var currentUser = await UserManager.GetUserAsync(user);
            account.UUID = currentUser.Id;
            account.Name = currentUser.UserName;
            account.Email = currentUser.Email;

            var acc = AccountModel.Find(account.Email);
            if (acc != null)
                account = acc;
            ///tmp

            account.AccRole = Role.User;
            return account;
        }

        return null;
    }
}