using DiunaBI.Application.DTOModels;
using DiunaBI.UI.Shared.Services;
using Microsoft.AspNetCore.Components;
using MudBlazor;
using System.Reflection;

namespace DiunaBI.UI.Shared.Pages.Layers;

public partial class Details : ComponentBase, IDisposable
{
    [Parameter]
    public Guid Id { get; set; }

    [Inject]
    private IDialogService DialogService { get; set; } = null!;

    [Inject]
    private LayerService LayerService { get; set; } = null!;

    [Inject]
    private JobService JobService { get; set; } = null!;

    [Inject]
    private EntityChangeHubService HubService { get; set; } = null!;

    [Inject]
    private NavigationManager NavigationManager { get; set; } = null!;

    [Inject]
    private ISnackbar Snackbar { get; set; } = null!;

    [Inject]
    private DateTimeHelper DateTimeHelper { get; set; } = null!;

    [Inject]
    private NumberFormatHelper NumberFormatHelper { get; set; } = null!;

    private LayerDto? layer;
    private List<RecordDto> records = new();
    private List<string> displayedColumns = new();
    private double valueSum = 0;
    private Dictionary<string, double> columnSums = new();
    private double totalSum = 0;
    private bool isLoading = false;
    private Guid? editingRecordId = null;
    private RecordDto? editingRecord = null;
    private bool isAddingNew = false;
    private RecordDto newRecord = new();
    private bool isEditable => layer?.Type == LayerType.Dictionary || layer?.Type == LayerType.Administration;
    private bool showHistoryTab => layer?.Type == LayerType.Administration || layer?.Type == LayerType.Dictionary;
    private bool showSummary => layer?.Type == LayerType.Import || layer?.Type == LayerType.Processed;

    // History tab state
    private bool isLoadingHistory = false;
    private bool isHistoryTabInitialized = false;
    private RecordDto? selectedRecordForHistory = null;
    private DeletedRecordDto? selectedDeletedRecordForHistory = null;
    private List<RecordHistoryDto> recordHistory = new();
    private List<DeletedRecordDto> deletedRecords = new();
    private Dictionary<Guid, string> userCache = new();

    protected override async Task OnInitializedAsync()
    {
        await DateTimeHelper.InitializeAsync();
        await LoadLayer();

        // Subscribe to SignalR entity changes
        HubService.EntityChanged += OnEntityChanged;
    }

    private async void OnEntityChanged(string module, string id, string operation)
    {
        // React to Layers or Records changes for this layer
        if (module.Equals("Layers", StringComparison.OrdinalIgnoreCase) ||
            module.Equals("Records", StringComparison.OrdinalIgnoreCase))
        {
            // Check if it's this layer or its records that changed
            if (Guid.TryParse(id, out var changedId))
            {
                if (module.Equals("Layers", StringComparison.OrdinalIgnoreCase) && changedId == Id)
                {
                    await InvokeAsync(async () =>
                    {
                        await LoadLayer();
                        StateHasChanged();
                    });
                }
                else if (module.Equals("Records", StringComparison.OrdinalIgnoreCase))
                {
                    // For records, we reload to get the latest data
                    await InvokeAsync(async () =>
                    {
                        await LoadLayer();
                        StateHasChanged();
                    });
                }
            }
        }
    }

    protected override async Task OnParametersSetAsync()
    {
        await LoadLayer();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (!isHistoryTabInitialized && !isLoadingHistory &&
            selectedRecordForHistory == null && selectedDeletedRecordForHistory == null &&
            deletedRecords.Count == 0)
        {
            await LoadDeletedRecordsAsync();
        }
    }

    private async Task LoadLayer()
    {
        isLoading = true;
        StateHasChanged();

        try
        {
            layer = await LayerService.GetLayerByIdAsync(Id);

            if (layer != null && layer.Records != null)
            {
                records = layer.Records.OrderBy(r => r.Code).ToList();
                CalculateDisplayedColumns();
                CalculateColumnSums();
                BuildUserCache();
            }
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error loading layer: {ex.Message}");
            Snackbar.Add("Error loading layer", Severity.Error);
        }
        finally
        {
            isLoading = false;
            StateHasChanged();
        }
    }

    private void CalculateDisplayedColumns()
    {
        displayedColumns.Clear();

        // Check which Value columns have data
        for (int i = 1; i <= 32; i++)
        {
            var columnName = $"Value{i}";
            var hasData = records.Any(r => GetRecordValueByName(r, columnName) != null);

            if (hasData)
            {
                displayedColumns.Add(columnName);
            }
        }

        // Check if Desc1 has data
        if (records.Any(r => !string.IsNullOrEmpty(r.Desc1)))
        {
            displayedColumns.Add("Description1");
        }
    }

    private void CalculateColumnSums()
    {
        columnSums.Clear();
        totalSum = 0;

        // Calculate sum for each displayed value column
        foreach (var columnName in displayedColumns.Where(c => c.StartsWith("Value")))
        {
            var sum = records
                .Select(r => GetRecordValueByName(r, columnName))
                .Where(v => v.HasValue)
                .Sum(v => v!.Value);

            columnSums[columnName] = sum;
            totalSum += sum;
        }

        // Keep valueSum for backward compatibility (Value1 sum)
        valueSum = columnSums.ContainsKey("Value1") ? columnSums["Value1"] : 0;
    }

    private string GetRecordValue(RecordDto record, string columnName)
    {
        if (columnName == "Description1")
        {
            return record.Desc1 ?? string.Empty;
        }

        var value = GetRecordValueByName(record, columnName);
        return NumberFormatHelper.FormatNumber(value);
    }

    private double? GetRecordValueByName(RecordDto record, string columnName)
    {
        var property = typeof(RecordDto).GetProperty(columnName, BindingFlags.Public | BindingFlags.Instance);
        if (property != null && property.PropertyType == typeof(double?))
        {
            return property.GetValue(record) as double?;
        }
        return null;
    }

    private void Export()
    {
        // TODO: Implement export functionality
        Snackbar.Add("Export functionality coming soon", Severity.Error);
    }

    private void ProcessLayer()
    {
        // TODO: Implement process layer functionality
        Snackbar.Add("Process layer functionality coming soon", Severity.Error);
    }

    private void GoBack()
    {
        NavigationManager.NavigateTo("/layers");
    }

    // Record editing methods
    private void StartEdit(RecordDto record)
    {
        editingRecordId = record.Id;
        editingRecord = new RecordDto
        {
            Id = record.Id,
            Code = record.Code,
            Desc1 = record.Desc1,
            LayerId = record.LayerId
        };
    }

    private void CancelEdit()
    {
        editingRecordId = null;
        editingRecord = null;
    }

    private async Task SaveEdit()
    {
        if (editingRecord == null || layer == null) return;

        if (string.IsNullOrWhiteSpace(editingRecord.Code))
        {
            Snackbar.Add("Code is required", Severity.Warning);
            return;
        }

        if (string.IsNullOrWhiteSpace(editingRecord.Desc1))
        {
            Snackbar.Add("Description is required", Severity.Warning);
            return;
        }

        try
        {
            var updated = await LayerService.UpdateRecordAsync(layer.Id, editingRecord.Id, editingRecord);
            if (updated != null)
            {
                var record = records.FirstOrDefault(r => r.Id == editingRecord.Id);
                if (record != null)
                {
                    record.Code = updated.Code;
                    record.Desc1 = updated.Desc1;
                    record.ModifiedAt = updated.ModifiedAt;
                }
                editingRecordId = null;
                editingRecord = null;
                Snackbar.Add("Record updated successfully", Severity.Success);
                StateHasChanged();
            }
            else
            {
                Snackbar.Add("Failed to update record", Severity.Error);
            }
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error updating record: {ex.Message}");
            Snackbar.Add("Error updating record", Severity.Error);
        }
    }

    private async Task DeleteRecord(RecordDto record)
    {
        if (layer == null) return;

        var result = await DialogService.ShowMessageBox(
            "Confirm Delete",
            $"Are you sure you want to delete record '{record.Code}'?",
            yesText: "Delete",
            cancelText: "Cancel");

        if (result == true)
        {
            try
            {
                var success = await LayerService.DeleteRecordAsync(layer.Id, record.Id);
                if (success)
                {
                    records.Remove(record);
                    CalculateDisplayedColumns();
                    CalculateColumnSums();
                    Snackbar.Add("Record deleted successfully", Severity.Success);
                }
                else
                {
                    Snackbar.Add("Failed to delete record", Severity.Error);
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error deleting record: {ex.Message}");
                Snackbar.Add("Error deleting record", Severity.Error);
            }
        }
    }

    private void StartAddNew()
    {
        isAddingNew = true;
        newRecord = new RecordDto { LayerId = layer?.Id ?? Guid.Empty };
    }

    private void CancelAddNew()
    {
        isAddingNew = false;
        newRecord = new();
    }

    private async Task SaveNewRecord()
    {
        if (layer == null) return;

        if (string.IsNullOrWhiteSpace(newRecord.Code))
        {
            Snackbar.Add("Code is required", Severity.Warning);
            return;
        }

        if (string.IsNullOrWhiteSpace(newRecord.Desc1))
        {
            Snackbar.Add("Description is required", Severity.Warning);
            return;
        }

        try
        {
            var created = await LayerService.CreateRecordAsync(layer.Id, newRecord);
            if (created != null)
            {
                records.Add(created);
                CalculateDisplayedColumns();
                CalculateColumnSums();
                isAddingNew = false;
                newRecord = new();
                Snackbar.Add("Record added successfully", Severity.Success);
            }
            else
            {
                Snackbar.Add("Failed to add record", Severity.Error);
            }
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error adding record: {ex.Message}");
            Snackbar.Add("Error adding record", Severity.Error);
        }
    }

    // History tab methods
    private async Task LoadDeletedRecordsAsync()
    {
        if (isHistoryTabInitialized || layer == null) return;

        isHistoryTabInitialized = true;

        try
        {
            Console.WriteLine($"Loading deleted records for layer {layer.Id}");
            deletedRecords = await LayerService.GetDeletedRecordsAsync(layer.Id);
            Console.WriteLine($"Loaded {deletedRecords.Count} deleted records");
            StateHasChanged();
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error loading deleted records: {ex.Message}");
            Console.Error.WriteLine($"Stack trace: {ex.StackTrace}");
            deletedRecords = new List<DeletedRecordDto>();
        }
    }

    private async Task OnRecordClickForHistory(TableRowClickEventArgs<RecordDto> args)
    {
        if (args.Item == null || layer == null) return;

        selectedRecordForHistory = args.Item;
        isLoadingHistory = true;
        StateHasChanged();

        try
        {
            recordHistory = await LayerService.GetRecordHistoryAsync(layer.Id, args.Item.Id);
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error loading record history: {ex.Message}");
            Snackbar.Add("Error loading record history", Severity.Error);
            recordHistory = new List<RecordHistoryDto>();
        }
        finally
        {
            isLoadingHistory = false;
            StateHasChanged();
        }
    }

    private void ClearHistorySelection()
    {
        selectedRecordForHistory = null;
        selectedDeletedRecordForHistory = null;
        recordHistory.Clear();
        isHistoryTabInitialized = false; // Reset so deleted records reload when returning to list
    }

    private async Task OnDeletedRecordClickForHistory(TableRowClickEventArgs<DeletedRecordDto> args)
    {
        if (args.Item == null || layer == null) return;

        selectedDeletedRecordForHistory = args.Item;
        selectedRecordForHistory = null;
        isLoadingHistory = true;
        StateHasChanged();

        try
        {
            recordHistory = await LayerService.GetRecordHistoryAsync(layer.Id, args.Item.RecordId);
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error loading deleted record history: {ex.Message}");
            Snackbar.Add("Error loading record history", Severity.Error);
            recordHistory = new List<RecordHistoryDto>();
        }
        finally
        {
            isLoadingHistory = false;
            StateHasChanged();
        }
    }

    private Color GetHistoryColor(string changeType)
    {
        return changeType switch
        {
            "Created" => Color.Success,
            "Updated" => Color.Info,
            "Deleted" => Color.Error,
            _ => Color.Default
        };
    }

    private void BuildUserCache()
    {
        userCache.Clear();

        if (layer == null) return;

        // Add layer-level users to cache
        if (layer.CreatedBy != null)
            userCache.TryAdd(layer.CreatedBy.Id, layer.CreatedBy.Username ?? string.Empty);
        if (layer.ModifiedBy != null)
            userCache.TryAdd(layer.ModifiedBy.Id, layer.ModifiedBy.Username ?? string.Empty);
    }

    private string GetModifiedByUsername(Guid userId)
    {
        return userCache.TryGetValue(userId, out var username) ? username : string.Empty;
    }

    // Run Now button methods
    private bool isRunningJob = false;

    private bool IsWorkerLayer()
    {
        if (layer?.Records == null) return false;

        var typeRecord = layer.Records.FirstOrDefault(x => x.Code == "Type");
        return typeRecord?.Desc1 == "ImportWorker" || typeRecord?.Desc1 == "ProcessWorker";
    }

    private async Task RunNow()
    {
        if (layer == null) return;

        isRunningJob = true;
        try
        {
            var result = await JobService.CreateJobForLayerAsync(layer.Id);

            if (result != null && result.Success)
            {
                if (result.Existing)
                {
                    Snackbar.Add($"Job already exists: {result.Message}", Severity.Info);
                }
                else
                {
                    Snackbar.Add("Job created successfully! Watch real-time status updates.", Severity.Success);
                }

                // Navigate to job detail page to see real-time updates
                NavigationManager.NavigateTo($"/jobs/{result.JobId}");
            }
            else
            {
                Snackbar.Add("Failed to create job", Severity.Error);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error creating job: {ex.Message}");
            Snackbar.Add($"Error creating job: {ex.Message}", Severity.Error);
        }
        finally
        {
            isRunningJob = false;
        }
    }

    public void Dispose()
    {
        HubService.EntityChanged -= OnEntityChanged;
    }
}
