@page "/deployment/instances"
@using ScadaLink.Security
@using ScadaLink.Commons.Entities.Instances
@using ScadaLink.Commons.Entities.Sites
@using ScadaLink.Commons.Entities.Templates
@using ScadaLink.Commons.Entities.Deployment
@using ScadaLink.Commons.Interfaces.Repositories
@using ScadaLink.Commons.Types.Enums
@using ScadaLink.DeploymentManager
@attribute [Authorize(Policy = AuthorizationPolicies.RequireDeployment)]
@inject ITemplateEngineRepository TemplateEngineRepository
@inject ISiteRepository SiteRepository
@inject IDeploymentManagerRepository DeploymentManagerRepository
@inject DeploymentService DeploymentService
@inject AuthenticationStateProvider AuthStateProvider
@inject NavigationManager NavigationManager

<div class="container-fluid mt-3">
    <div class="d-flex justify-content-between align-items-center mb-3">
        <h4 class="mb-0">Instances</h4>
        <button class="btn btn-primary btn-sm" @onclick='() => NavigationManager.NavigateTo("/deployment/instances/create")'>Create Instance</button>
    </div>

    <ToastNotification @ref="_toast" />
    <ConfirmDialog @ref="_confirmDialog" />

    @if (_loading)
    {
        <LoadingSpinner IsLoading="true" />
    }
    else if (_errorMessage != null)
    {
        <div class="alert alert-danger">@_errorMessage</div>
    }
    else
    {
        @* Filters *@
        <div class="row mb-3 g-2">
            <div class="col-md-2">
                <label class="form-label small">Site</label>
                <select class="form-select form-select-sm" @bind="_filterSiteId" @bind:after="ApplyFilters">
                    <option value="0">All Sites</option>
                    @foreach (var site in _sites)
                    {
                        <option value="@site.Id">@site.Name</option>
                    }
                </select>
            </div>
            <div class="col-md-2">
                <label class="form-label small">Template</label>
                <select class="form-select form-select-sm" @bind="_filterTemplateId" @bind:after="ApplyFilters">
                    <option value="0">All Templates</option>
                    @foreach (var tmpl in _templates)
                    {
                        <option value="@tmpl.Id">@tmpl.Name</option>
                    }
                </select>
            </div>
            <div class="col-md-2">
                <label class="form-label small">Status</label>
                <select class="form-select form-select-sm" @bind="_filterStatus" @bind:after="ApplyFilters">
                    <option value="">All Statuses</option>
                    <option value="NotDeployed">Not Deployed</option>
                    <option value="Enabled">Enabled</option>
                    <option value="Disabled">Disabled</option>
                </select>
            </div>
            <div class="col-md-3">
                <label class="form-label small">Search</label>
                <input type="text" class="form-control form-control-sm" placeholder="Instance name..."
                       @bind="_filterSearch" @bind:event="oninput" @bind:after="ApplyFilters" />
            </div>
            <div class="col-md-3 d-flex align-items-end">
                <button class="btn btn-outline-secondary btn-sm" @onclick="LoadDataAsync">Refresh</button>
            </div>
        </div>

        <table class="table table-sm table-striped table-hover">
            <thead class="table-dark">
                <tr>
                    <th>Instance Name</th>
                    <th>Template</th>
                    <th>Site</th>
                    <th>Area</th>
                    <th>Status</th>
                    <th>Staleness</th>
                    <th style="width: 240px;">Actions</th>
                </tr>
            </thead>
            <tbody>
                @if (_filteredInstances.Count == 0)
                {
                    <tr>
                        <td colspan="7" class="text-muted text-center">No instances match the current filters.</td>
                    </tr>
                }
                @foreach (var inst in _pagedInstances)
                {
                    <tr>
                        <td><strong>@inst.UniqueName</strong></td>
                        <td>@GetTemplateName(inst.TemplateId)</td>
                        <td>@GetSiteName(inst.SiteId)</td>
                        <td>@(inst.AreaId.HasValue ? GetAreaName(inst.AreaId.Value) : "—")</td>
                        <td>
                            <span class="badge @GetStateBadge(inst.State)">@inst.State</span>
                        </td>
                        <td>
                            @{
                                var isStale = _stalenessMap.GetValueOrDefault(inst.Id);
                            }
                            @if (inst.State == InstanceState.NotDeployed)
                            {
                                <span class="text-muted small">—</span>
                            }
                            else if (isStale)
                            {
                                <span class="badge bg-warning text-dark" title="Template changes pending">Stale</span>
                            }
                            else
                            {
                                <span class="badge bg-light text-dark">Current</span>
                            }
                        </td>
                        <td>
                            <button class="btn btn-outline-primary btn-sm py-0 px-1 me-1"
                                    @onclick="() => DeployInstance(inst)" disabled="@_actionInProgress"
                                    title="Flatten template and send config to site">@(isStale ? "Redeploy" : "Deploy")</button>
                            @if (inst.State == InstanceState.Enabled)
                            {
                                <button class="btn btn-outline-warning btn-sm py-0 px-1 me-1"
                                        @onclick="() => DisableInstance(inst)" disabled="@_actionInProgress">Disable</button>
                            }
                            else if (inst.State == InstanceState.Disabled)
                            {
                                <button class="btn btn-outline-success btn-sm py-0 px-1 me-1"
                                        @onclick="() => EnableInstance(inst)" disabled="@_actionInProgress">Enable</button>
                            }
                            <button class="btn btn-outline-info btn-sm py-0 px-1 me-1"
                                    @onclick='() => NavigationManager.NavigateTo($"/deployment/instances/{inst.Id}/configure")'>Configure</button>
                            <button class="btn btn-outline-info btn-sm py-0 px-1 me-1"
                                    @onclick="() => ShowDiff(inst)" disabled="@(_actionInProgress || inst.State == InstanceState.NotDeployed)">Diff</button>
                            <button class="btn btn-outline-danger btn-sm py-0 px-1"
                                    @onclick="() => DeleteInstance(inst)" disabled="@_actionInProgress">Delete</button>
                        </td>
                    </tr>
                }
            </tbody>
        </table>

        @* Pagination *@
        @if (_totalPages > 1)
        {
            <nav>
                <ul class="pagination pagination-sm justify-content-end">
                    <li class="page-item @(_currentPage <= 1 ? "disabled" : "")">
                        <button class="page-link" @onclick="() => GoToPage(_currentPage - 1)">Previous</button>
                    </li>
                    @for (int i = 1; i <= _totalPages; i++)
                    {
                        var page = i;
                        <li class="page-item @(page == _currentPage ? "active" : "")">
                            <button class="page-link" @onclick="() => GoToPage(page)">@(page)</button>
                        </li>
                    }
                    <li class="page-item @(_currentPage >= _totalPages ? "disabled" : "")">
                        <button class="page-link" @onclick="() => GoToPage(_currentPage + 1)">Next</button>
                    </li>
                </ul>
            </nav>
        }
        <div class="text-muted small">
            @_filteredInstances.Count instance(s) total
        </div>

        @* Diff Modal *@
        @if (_showDiffModal)
        {
            <div class="modal d-block" tabindex="-1" style="background-color: rgba(0,0,0,0.5);">
                <div class="modal-dialog modal-lg">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h5 class="modal-title">Deployment Diff — @_diffInstanceName</h5>
                            <button type="button" class="btn-close" @onclick="() => _showDiffModal = false"></button>
                        </div>
                        <div class="modal-body">
                            @if (_diffLoading)
                            {
                                <LoadingSpinner IsLoading="true" />
                            }
                            else if (_diffError != null)
                            {
                                <div class="alert alert-danger">@_diffError</div>
                            }
                            else if (_diffResult != null)
                            {
                                <div class="mb-2">
                                    <span class="badge @(_diffResult.IsStale ? "bg-warning text-dark" : "bg-success")">
                                        @(_diffResult.IsStale ? "Stale — changes pending" : "Current")
                                    </span>
                                    <span class="text-muted small ms-2">
                                        Deployed: @_diffResult.DeployedRevisionHash[..8]
                                        | Current: @_diffResult.CurrentRevisionHash[..8]
                                        | Deployed at: @_diffResult.DeployedAt.LocalDateTime.ToString("yyyy-MM-dd HH:mm")
                                    </span>
                                </div>
                                @if (!_diffResult.IsStale)
                                {
                                    <p class="text-muted">No differences between deployed and current configuration.</p>
                                }
                                else
                                {
                                    <p class="text-muted small">The deployed revision hash differs from the current template-derived hash. Redeploy to apply changes.</p>
                                }
                            }
                        </div>
                        <div class="modal-footer">
                            <button class="btn btn-secondary btn-sm" @onclick="() => _showDiffModal = false">Close</button>
                        </div>
                    </div>
                </div>
            </div>
        }
    }
</div>

@code {
    private async Task<string> GetCurrentUserAsync()
    {
        var authState = await AuthStateProvider.GetAuthenticationStateAsync();
        return authState.User.FindFirst("Username")?.Value ?? "unknown";
    }

    private List<Instance> _allInstances = new();
    private List<Instance> _filteredInstances = new();
    private List<Instance> _pagedInstances = new();
    private List<Site> _sites = new();
    private List<Template> _templates = new();
    private List<Area> _allAreas = new();
    private Dictionary<int, bool> _stalenessMap = new();
    private bool _loading = true;
    private string? _errorMessage;
    private bool _actionInProgress;

    private int _filterSiteId;
    private int _filterTemplateId;
    private string _filterStatus = string.Empty;
    private string _filterSearch = string.Empty;

    private int _currentPage = 1;
    private int _totalPages;
    private const int PageSize = 25;

    private ToastNotification _toast = default!;
    private ConfirmDialog _confirmDialog = default!;

    protected override async Task OnInitializedAsync()
    {
        await LoadDataAsync();
    }

    private async Task LoadDataAsync()
    {
        _loading = true;
        _errorMessage = null;
        try
        {
            _allInstances = (await TemplateEngineRepository.GetAllInstancesAsync()).ToList();
            _sites = (await SiteRepository.GetAllSitesAsync()).ToList();
            _templates = (await TemplateEngineRepository.GetAllTemplatesAsync()).ToList();

            // Load areas for display
            _allAreas.Clear();
            foreach (var site in _sites)
            {
                var areas = await TemplateEngineRepository.GetAreasBySiteIdAsync(site.Id);
                _allAreas.AddRange(areas);
            }

            // Check staleness for deployed instances
            _stalenessMap.Clear();
            foreach (var inst in _allInstances.Where(i => i.State != InstanceState.NotDeployed))
            {
                try
                {
                    var comparison = await DeploymentService.GetDeploymentComparisonAsync(inst.Id);
                    _stalenessMap[inst.Id] = comparison.IsSuccess && comparison.Value.IsStale;
                }
                catch
                {
                    _stalenessMap[inst.Id] = false;
                }
            }

            ApplyFilters();
        }
        catch (Exception ex)
        {
            _errorMessage = $"Failed to load instances: {ex.Message}";
        }
        _loading = false;
    }

    private void ApplyFilters()
    {
        _filteredInstances = _allInstances.Where(i =>
        {
            if (_filterSiteId > 0 && i.SiteId != _filterSiteId) return false;
            if (_filterTemplateId > 0 && i.TemplateId != _filterTemplateId) return false;
            if (!string.IsNullOrEmpty(_filterStatus) && i.State.ToString() != _filterStatus) return false;
            if (!string.IsNullOrWhiteSpace(_filterSearch) &&
                !i.UniqueName.Contains(_filterSearch, StringComparison.OrdinalIgnoreCase)) return false;
            return true;
        }).OrderBy(i => i.UniqueName).ToList();

        _totalPages = Math.Max(1, (int)Math.Ceiling(_filteredInstances.Count / (double)PageSize));
        if (_currentPage > _totalPages) _currentPage = 1;
        UpdatePage();
    }

    private void GoToPage(int page)
    {
        if (page < 1 || page > _totalPages) return;
        _currentPage = page;
        UpdatePage();
    }

    private void UpdatePage()
    {
        _pagedInstances = _filteredInstances
            .Skip((_currentPage - 1) * PageSize)
            .Take(PageSize)
            .ToList();
    }

    private string GetTemplateName(int templateId) =>
        _templates.FirstOrDefault(t => t.Id == templateId)?.Name ?? $"#{templateId}";

    private string GetSiteName(int siteId) =>
        _sites.FirstOrDefault(s => s.Id == siteId)?.Name ?? $"#{siteId}";

    private string GetAreaName(int areaId) =>
        _allAreas.FirstOrDefault(a => a.Id == areaId)?.Name ?? $"#{areaId}";

    private static string GetStateBadge(InstanceState state) => state switch
    {
        InstanceState.Enabled => "bg-success",
        InstanceState.Disabled => "bg-secondary",
        InstanceState.NotDeployed => "bg-light text-dark",
        _ => "bg-secondary"
    };

    private async Task EnableInstance(Instance inst)
    {
        _actionInProgress = true;
        try
        {
            var user = await GetCurrentUserAsync();
            var result = await DeploymentService.EnableInstanceAsync(inst.Id, user);
            if (result.IsSuccess)
            {
                _toast.ShowSuccess($"Instance '{inst.UniqueName}' enabled.");
                await LoadDataAsync();
            }
            else
            {
                _toast.ShowError($"Enable failed: {result.Error}");
            }
        }
        catch (Exception ex)
        {
            _toast.ShowError($"Enable failed: {ex.Message}");
        }
        _actionInProgress = false;
    }

    private async Task DisableInstance(Instance inst)
    {
        var confirmed = await _confirmDialog.ShowAsync(
            $"Disable instance '{inst.UniqueName}'? The instance actor will be stopped.",
            "Disable Instance");
        if (!confirmed) return;

        _actionInProgress = true;
        try
        {
            var user = await GetCurrentUserAsync();
            var result = await DeploymentService.DisableInstanceAsync(inst.Id, user);
            if (result.IsSuccess)
            {
                _toast.ShowSuccess($"Instance '{inst.UniqueName}' disabled.");
                await LoadDataAsync();
            }
            else
            {
                _toast.ShowError($"Disable failed: {result.Error}");
            }
        }
        catch (Exception ex)
        {
            _toast.ShowError($"Disable failed: {ex.Message}");
        }
        _actionInProgress = false;
    }

    private async Task DeployInstance(Instance inst)
    {
        _actionInProgress = true;
        try
        {
            var user = await GetCurrentUserAsync();
            var result = await DeploymentService.DeployInstanceAsync(inst.Id, user);
            if (result.IsSuccess)
            {
                _toast.ShowSuccess($"Instance '{inst.UniqueName}' deployed (revision {result.Value.RevisionHash?[..8]}).");
                await LoadDataAsync();
            }
            else
            {
                _toast.ShowError($"Deploy failed: {result.Error}");
            }
        }
        catch (Exception ex)
        {
            _toast.ShowError($"Deploy failed: {ex.Message}");
        }
        _actionInProgress = false;
    }

    private async Task DeleteInstance(Instance inst)
    {
        var confirmed = await _confirmDialog.ShowAsync(
            $"Delete instance '{inst.UniqueName}'? This will remove it from the site. Store-and-forward messages will NOT be cleared.",
            "Delete Instance");
        if (!confirmed) return;

        _actionInProgress = true;
        try
        {
            var user = await GetCurrentUserAsync();
            var result = await DeploymentService.DeleteInstanceAsync(inst.Id, user);
            if (result.IsSuccess)
            {
                _toast.ShowSuccess($"Instance '{inst.UniqueName}' deleted.");
                await LoadDataAsync();
            }
            else
            {
                _toast.ShowError($"Delete failed: {result.Error}");
            }
        }
        catch (Exception ex)
        {
            _toast.ShowError($"Delete failed: {ex.Message}");
        }
        _actionInProgress = false;
    }

    // Diff state
    private bool _showDiffModal;
    private bool _diffLoading;
    private string? _diffError;
    private string _diffInstanceName = string.Empty;
    private DeploymentComparisonResult? _diffResult;

    private async Task ShowDiff(Instance inst)
    {
        _showDiffModal = true;
        _diffLoading = true;
        _diffError = null;
        _diffResult = null;
        _diffInstanceName = inst.UniqueName;
        try
        {
            var result = await DeploymentService.GetDeploymentComparisonAsync(inst.Id);
            if (result.IsSuccess)
            {
                _diffResult = result.Value;
            }
            else
            {
                _diffError = result.Error;
            }
        }
        catch (Exception ex)
        {
            _diffError = $"Failed to load diff: {ex.Message}";
        }
        _diffLoading = false;
    }

}
