@page "/User/{CodContact}/{IsContact:bool}"
@attribute [Authorize]
@using AutoMapper
@using salesbook.Shared.Components.Layout
@using salesbook.Shared.Core.Entity
@using salesbook.Shared.Core.Interface
@using salesbook.Shared.Components.Layout.Spinner
@using salesbook.Shared.Core.Dto
@using salesbook.Shared.Components.SingleElements
@using salesbook.Shared.Core.Dto.Activity
@using salesbook.Shared.Core.Dto.JobProgress
@using salesbook.Shared.Core.Dto.PageState
@using salesbook.Shared.Core.Interface.IntegryApi
@implements IAsyncDisposable
@inject IManageDataService ManageData
@inject IMapper Mapper
@inject IDialogService Dialog
@inject IIntegryApiService IntegryApiService
@inject UserPageState UserState

<HeaderLayout BackTo="Indietro"
              LabelSave="Modifica"
              OnSave="() => OpenUserForm(Anag)"
              Back="true"
              BackOnTop="true"
              Title=""
              ShowProfile="false"/>

@if (IsLoading)
{
    <SpinnerLayout FullScreen="true"/>
}
else
{
    <div class="container content pb-safe-area" style="overflow: auto;" id="topPage">
        <div class="container-primary-info">
            <div class="section-primary-info">
                <MudAvatar Style="height: 70px; width: 70px; font-size: 2rem; font-weight: bold" Variant="@(IsContact ? Variant.Filled : Variant.Outlined)" Color="Color.Secondary">
                    @UtilityString.ExtractInitials(Anag.RagSoc)
                </MudAvatar>

                <div class="personal-info">
                    <span class="info-nome">@Anag.RagSoc</span>
                    @if (!string.IsNullOrEmpty(Anag.Indirizzo))
                    {
                        <span class="info-section">@Anag.Indirizzo</span>
                    }
                    @if (!string.IsNullOrEmpty(Anag.Cap) && !string.IsNullOrEmpty(Anag.Citta) && !string.IsNullOrEmpty(Anag.Prov))
                    {
                        <span class="info-section">@($"{Anag.Cap} - {Anag.Citta} ({Anag.Prov})")</span>
                    }
                </div>
            </div>

            <div class="divider"></div>

            <div class="section-info">
                @if (Agente != null)
                {
                    <div class="section-personal-info">
                        <div>
                            <span class="info-title">Agente</span>
                            <span class="info-text">@Agente.FullName</span>
                        </div>
                    </div>
                }

                @if (!string.IsNullOrEmpty(Anag.Telefono))
                {
                    <div class="section-personal-info">
                        <div>
                            <span class="info-title">Telefono</span>
                            <span class="info-text">@Anag.Telefono</span>
                        </div>
                    </div>
                }

                @if (!string.IsNullOrEmpty(Anag.PartIva))
                {
                    <div class="section-personal-info">
                        <div>
                            <span class="info-title">P. IVA</span>
                            <span class="info-text">@Anag.PartIva</span>
                        </div>
                    </div>
                }

                @if (!string.IsNullOrEmpty(Anag.EMail))
                {
                    <div class="section-personal-info">
                        <div>
                            <span class="info-title">E-mail</span>
                            <span class="info-text">@Anag.EMail</span>
                        </div>
                    </div>
                }
            </div>
        </div>
        
        <div class="tab-section">
            <input type="radio" class="tab-toggle" name="tab-toggle" id="tab1" checked="@(ActiveTab == 0)">
            <input type="radio" class="tab-toggle" name="tab-toggle" id="tab2" checked="@(ActiveTab == 1)">
            <input type="radio" class="tab-toggle" name="tab-toggle" id="tab3" checked="@(ActiveTab == 2)">

            <div class="box">
                <ul class="tab-list">
                    <li class="tab-item">
                        <label class="tab-trigger" for="tab1" @onclick="() => SwitchTab(0)">Contatti</label>
                    </li>
                    <li class="tab-item">
                        <label class="tab-trigger" for="tab2" @onclick="() => SwitchTab(1)">Commesse</label>
                    </li>
                    <li class="tab-item">
                        <label class="tab-trigger" for="tab3" @onclick="() => SwitchTab(2)">Attivitą</label>
                    </li>
                </ul>
            </div>

            <div class="tab-container">
                <!-- Tab Contatti -->
                <div class="tab-content" style="display: @(ActiveTab == 0 ? "block" : "none")">
                    @if (PersRif?.Count > 0)
                    {
                        <div class="container-pers-rif">
                            @foreach (var person in PersRif)
                            {
                                <ContactCard Contact="person"/>
                                @if (person != PersRif.Last())
                                {
                                    <div class="divider"></div>
                                }
                            }
                        </div>
                    }

                    <div class="container-button">
                        <div class="divider"></div>

                        <MudButton Class="button-settings infoText"
                                   FullWidth="true"
                                   Size="Size.Medium"
                                   StartIcon="@Icons.Material.Rounded.Add"
                                   OnClick="OpenPersRifForm"
                                   Variant="Variant.Outlined">
                            Aggiungi contatto
                        </MudButton>
                    </div>
                </div>

                <!-- Tab Commesse -->
                <div class="tab-content" style="display: @(ActiveTab == 1 ? "block" : "none")">
                    @if (IsLoadingCommesse)
                    {
                        <MudProgressLinear Color="Color.Primary" Indeterminate="true" Class="my-7"/>
                    }
                    else if (Commesse?.Count == 0)
                    {
                        <NoDataAvailable Text="Nessuna commessa presente"/>
                    }
                    else if (Commesse != null)
                    {
                        <!-- Filtri e ricerca -->
                        <div class="input-card clearButton custom-border-bottom">
                            <MudTextField T="string?"
                                          Placeholder="Cerca..."
                                          Variant="Variant.Text"
                                          @bind-Value="SearchTermCommesse"
                                          AdornmentIcon="@Icons.Material.Rounded.Search"
                                          Adornment="Adornment.Start"
                                          OnDebounceIntervalElapsed="() => ApplyFiltersCommesse()"
                                          DebounceInterval="500"/>
                        </div>

                        <div class="commesse-container">
                            @if (IsLoadingSteps)
                            {
                                <MudProgressLinear Color="Color.Primary" Indeterminate="true" Class="my-3"/>
                            }

                            @foreach (var commessa in CurrentPageCommesse)
                            {
                                <div class="commessa-wrapper" style="@(IsLoadingStep(commessa.CodJcom) ? "opacity: 0.7;" : "")">
                                    @if (Steps.TryGetValue(commessa.CodJcom, out var steps))
                                    {
                                        <CommessaCard Steps="@steps" RagSoc="@Anag.RagSoc" Commessa="commessa"/>
                                    }
                                    else
                                    {
                                        <CommessaCard Steps="null" RagSoc="@Anag.RagSoc" Commessa="commessa"/>
                                        @if (IsLoadingStep(commessa.CodJcom))
                                        {
                                            <MudProgressLinear Indeterminate="true" Color="Color.Primary" Class="my-1" Style="height: 2px;"/>
                                        }
                                    }
                                </div>
                            }

                            @if (TotalPagesCommesse > 1)
                            {
                                <div class="custom-pagination">
                                    <MudPagination BoundaryCount="1" MiddleCount="1" Count="@TotalPagesCommesse"
                                                   @bind-Selected="SelectedPageCommesse"
                                                   Color="Color.Primary"/>
                                </div>

                                <div class="SelectedPageSize">
                                    <MudSelect @bind-Value="SelectedPageSizeCommesse"
                                               Variant="Variant.Text"
                                               Label="Elementi per pagina"
                                               Dense="true"
                                               Style="width: 100%;">
                                        <MudSelectItem Value="5">5</MudSelectItem>
                                        <MudSelectItem Value="10">10</MudSelectItem>
                                        <MudSelectItem Value="15">15</MudSelectItem>
                                    </MudSelect>
                                </div>
                            }
                        </div>
                    }
                </div>

                <!-- Tab Attivitą -->
                <div class="tab-content" style="display: @(ActiveTab == 2 ? "block" : "none")">
                    @if (ActivityIsLoading)
                    {
                        <MudProgressLinear Color="Color.Primary" Indeterminate="true" Class="my-7"/>
                    }
                    else if (ActivityList?.Count == 0)
                    {
                        <NoDataAvailable Text="Nessuna attivitą presente"/>
                    }
                    else if (ActivityList != null)
                    {
                        <!-- Filtri e ricerca -->
                        <div class="input-card clearButton custom-border-bottom">
                            <MudTextField T="string?"
                                          Placeholder="Cerca..."
                                          Variant="Variant.Text"
                                          AdornmentIcon="@Icons.Material.Rounded.Search"
                                          Adornment="Adornment.Start"
                                          @bind-Value="SearchTermActivity"
                                          OnDebounceIntervalElapsed="() => ApplyFiltersActivity()"
                                          DebounceInterval="500"/>
                        </div>

                        <div class="attivita-container">
                            @foreach (var activity in CurrentPageActivity)
                            {
                                <ActivityCard ShowDate="true" Activity="activity"/>
                            }

                            @if (TotalPagesActivity > 1)
                            {
                                <div class="custom-pagination">
                                    <MudPagination BoundaryCount="1" MiddleCount="1" Count="@TotalPagesActivity"
                                                   @bind-Selected="CurrentPageActivityIndex"
                                                   Color="Color.Primary"/>
                                </div>

                                <div class="SelectedPageSize">
                                    <MudSelect @bind-Value="SelectedPageSizeActivity"
                                               Variant="Variant.Text"
                                               Label="Elementi per pagina"
                                               Dense="true"
                                               Style="width: 100%;">
                                        <MudSelectItem Value="5">5</MudSelectItem>
                                        <MudSelectItem Value="15">15</MudSelectItem>
                                        <MudSelectItem Value="30">30</MudSelectItem>
                                    </MudSelect>
                                </div>
                            }
                        </div>
                    }
                </div>
            </div>

            <MudScrollToTop Selector="#topPage" VisibleCssClass="visible absolute" TopOffset="100" HiddenCssClass="invisible">
                <MudFab Size="Size.Small" Color="Color.Primary" StartIcon="@Icons.Material.Rounded.KeyboardArrowUp"/>
            </MudScrollToTop>
        </div>
    </div>
}

@code {
    [Parameter] public string CodContact { get; set; } = string.Empty;
    [Parameter] public bool IsContact { get; set; }

    // Dati principali
    private ContactDTO Anag { get; set; } = new();
    private List<PersRifDTO>? PersRif { get; set; }
    private List<JtbComt>? Commesse { get; set; }
    private List<ActivityDTO> ActivityList { get; set; } = [];
    private StbUser? Agente { get; set; }
    private Dictionary<string, List<CRMJobStepDTO>?> Steps { get; set; } = new();

    // Stati di caricamento
    private bool IsLoading { get; set; } = true;
    private bool IsLoadingCommesse { get; set; } = true;
    private bool ActivityIsLoading { get; set; } = true;
    private bool IsLoadingSteps { get; set; }
    private readonly HashSet<string> _loadingSteps = [];

    // Gestione tab
    private int ActiveTab { get; set; }

    // Paginazione e filtri per COMMESSE
    private int _selectedPageCommesse = 1;
    private int _selectedPageSizeCommesse = 5;
    private string _searchTermCommesse = string.Empty;
    private List<JtbComt> _filteredCommesse = [];

    // Paginazione e filtri per ATTIVITĄ
    private int _currentPageActivity = 1;
    private int _selectedPageSizeActivity = 5;
    private string _searchTermActivity = string.Empty;
    private List<ActivityDTO> _filteredActivity = [];

    // Cancellation tokens per gestire le richieste asincrone
    private CancellationTokenSource? _loadingCts;
    private CancellationTokenSource? _stepsCts;

    // Timer per il debounce della ricerca
    private Timer? _searchTimerCommesse;
    private Timer? _searchTimerActivity;
    private const int SearchDelayMs = 300;

    #region Properties per Commesse

    private int SelectedPageCommesse
    {
        get => _selectedPageCommesse;
        set
        {
            if (_selectedPageCommesse == value) return;
            _selectedPageCommesse = value;
            _ = LoadStepsForCurrentPageAsync();
        }
    }

    private int SelectedPageSizeCommesse
    {
        get => _selectedPageSizeCommesse;
        set
        {
            if (_selectedPageSizeCommesse == value) return;
            _selectedPageSizeCommesse = value;
            _selectedPageCommesse = 1;
            ApplyFiltersCommesse();
            _ = LoadStepsForCurrentPageAsync();
        }
    }

    private string SearchTermCommesse
    {
        get => _searchTermCommesse;
        set
        {
            if (_searchTermCommesse == value) return;
            _searchTermCommesse = value;

            _searchTimerCommesse?.Dispose();
            _searchTimerCommesse = new Timer(async _ => await InvokeAsync(ApplyFiltersCommesse), null, SearchDelayMs, Timeout.Infinite);
        }
    }

    private List<JtbComt> FilteredCommesse
    {
        get => _filteredCommesse;
        set
        {
            _filteredCommesse = value;
            StateHasChanged();
        }
    }

    private int TotalPagesCommesse =>
        FilteredCommesse.Count == 0 ? 1 : (int)Math.Ceiling(FilteredCommesse.Count / (double)SelectedPageSizeCommesse);

    private IEnumerable<JtbComt> CurrentPageCommesse =>
        FilteredCommesse.Skip((SelectedPageCommesse - 1) * SelectedPageSizeCommesse).Take(SelectedPageSizeCommesse);

    #endregion

    #region Properties per Attivitą

    private int CurrentPageActivityIndex
    {
        get => _currentPageActivity;
        set
        {
            if (_currentPageActivity == value) return;
            _currentPageActivity = value;
            StateHasChanged();
        }
    }

    private int SelectedPageSizeActivity
    {
        get => _selectedPageSizeActivity;
        set
        {
            if (_selectedPageSizeActivity == value) return;
            _selectedPageSizeActivity = value;
            _currentPageActivity = 1;
            ApplyFiltersActivity();
        }
    }

    private string SearchTermActivity
    {
        get => _searchTermActivity;
        set
        {
            if (_searchTermActivity == value) return;
            _searchTermActivity = value;

            _searchTimerActivity?.Dispose();
            _searchTimerActivity = new Timer(async _ => await InvokeAsync(ApplyFiltersActivity), null, SearchDelayMs, Timeout.Infinite);
        }
    }

    private List<ActivityDTO> FilteredActivity
    {
        get => _filteredActivity;
        set
        {
            _filteredActivity = value;
            InvokeAsync(StateHasChanged);
        }
    }

    private int TotalPagesActivity =>
        FilteredActivity.Count == 0 ? 1 : (int)Math.Ceiling(FilteredActivity.Count / (double)SelectedPageSizeActivity);

    private IEnumerable<ActivityDTO> CurrentPageActivity =>
        FilteredActivity.Skip((CurrentPageActivityIndex - 1) * SelectedPageSizeActivity).Take(SelectedPageSizeActivity);

    #endregion

    #region Lifecycle Methods

    protected override async Task OnInitializedAsync()
    {
        try
        {
            _loadingCts = new CancellationTokenSource();

            if (UserState.CodUser?.Equals(CodContact) == true)
            {
                LoadDataFromSession();
            }
            else
            {
                await LoadDataAsync();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Errore in OnInitializedAsync: {ex.Message}");
        }
        finally
        {
            IsLoading = false;
            StateHasChanged();
        }
    }

    public async ValueTask DisposeAsync()
    {
        _loadingCts?.CancelAsync();
        _loadingCts?.Dispose();
        _stepsCts?.CancelAsync();
        _stepsCts?.Dispose();
        _searchTimerCommesse?.DisposeAsync();
        _searchTimerActivity?.DisposeAsync();
    }

    #endregion

    #region Data Loading Methods

    private async Task LoadDataAsync()
    {
        try
        {
            await LoadAnagAsync();
            await LoadPersRifAsync();
            _ = LoadActivity();

            if (!string.IsNullOrEmpty(Anag.CodVage))
            {
                Agente = (await ManageData.GetTable<StbUser>(x => x.UserCode != null && x.UserCode.Equals(Anag.CodVage)))
                    .LastOrDefault();
            }

            SaveDataToSession();

            _ = Task.Run(async () => await LoadCommesseAsync());
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Errore nel caricamento dati: {ex.Message}");
        }
    }

    private async Task LoadAnagAsync()
    {
        if (IsContact)
        {
            var clie = (await ManageData.GetTable<AnagClie>(x => x.CodAnag!.Equals(CodContact))).Last();
            Anag = Mapper.Map<ContactDTO>(clie);
        }
        else
        {
            var pros = (await ManageData.GetTable<PtbPros>(x => x.CodPpro!.Equals(CodContact))).Last();
            Anag = Mapper.Map<ContactDTO>(pros);
        }
    }

    private async Task LoadPersRifAsync()
    {
        if (IsContact)
        {
            var pers = await ManageData.GetTable<VtbCliePersRif>(x => x.CodAnag!.Equals(Anag.CodContact));
            PersRif = Mapper.Map<List<PersRifDTO>>(pers);
        }
        else
        {
            var pers = await ManageData.GetTable<PtbProsRif>(x => x.CodPpro!.Equals(Anag.CodContact));
            PersRif = Mapper.Map<List<PersRifDTO>>(pers);
        }
    }

    private async Task LoadActivity()
    {
        await Task.Run(async () =>
        {
            var activities = await IntegryApiService.RetrieveActivity(new CRMRetrieveActivityRequestDTO { CodAnag = Anag.CodContact });
            ActivityList = (await ManageData.MapActivity(activities)).OrderByDescending(x =>
                (x.EffectiveTime ?? x.EstimatedTime) ?? x.DataInsAct
            ).ToList();
        });

        UserState.Activitys = ActivityList;

        ApplyFiltersActivity();

        ActivityIsLoading = false;
        StateHasChanged();
    }

    private async Task LoadCommesseAsync()
    {
        try
        {
            IsLoadingCommesse = true;

            Commesse = await ManageData.GetTable<JtbComt>(x => x.CodAnag != null && x.CodAnag.Equals(CodContact));

            Commesse = Commesse?
                .OrderByDescending(x => x.CodJcom)
                .ToList();

            UserState.Commesse = Commesse;

            ApplyFiltersCommesse();

            await LoadStepsForCurrentPageAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Errore nel caricamento commesse: {ex.Message}");
        }
        finally
        {
            IsLoadingCommesse = false;
            await InvokeAsync(StateHasChanged);
        }
    }

    private void LoadDataFromSession()
    {
        Anag = UserState.Anag;
        PersRif = UserState.PersRif;
        Commesse = UserState.Commesse;
        Agente = UserState.Agente;
        Steps = UserState.Steps;
        ActivityList = UserState.Activitys;

        if (ActiveTab != UserState.ActiveTab)
            SwitchTab(UserState.ActiveTab);

        ApplyFiltersCommesse();
        ApplyFiltersActivity();

        IsLoadingCommesse = false;
        ActivityIsLoading = false;
    }

    private void SaveDataToSession()
    {
        UserState.CodUser = CodContact;
        UserState.Anag = Anag;
        UserState.PersRif = PersRif;
        UserState.Agente = Agente;
        UserState.Steps = Steps;
        UserState.Activitys = ActivityList;
    }

    #endregion

    #region Steps Loading Methods

    private async Task LoadStepsForCurrentPageAsync()
    {
        if (CurrentPageCommesse?.Any() != true) return;

        try
        {
            _stepsCts?.Cancel();
            _stepsCts = new CancellationTokenSource();
            var token = _stepsCts.Token;

            IsLoadingSteps = true;

            var tasksToLoad = new List<Task>();
            var semaphore = new SemaphoreSlim(3); // Limita a 3 richieste simultanee

            foreach (var commessa in CurrentPageCommesse.Where(c => !Steps.ContainsKey(c.CodJcom)))
            {
                if (token.IsCancellationRequested) break;

                tasksToLoad.Add(LoadStepForCommessaAsync(commessa.CodJcom, semaphore, token));
            }

            if (tasksToLoad.Any())
            {
                await Task.WhenAll(tasksToLoad);
                UserState.Steps = Steps;
            }
        }
        catch (OperationCanceledException)
        {
            // Operazione annullata, non fare nulla
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Errore nel caricamento steps: {ex.Message}");
        }
        finally
        {
            IsLoadingSteps = false;
            await InvokeAsync(StateHasChanged);
        }
    }

    private async Task LoadStepForCommessaAsync(string codJcom, SemaphoreSlim semaphore, CancellationToken token)
    {
        await semaphore.WaitAsync(token);

        try
        {
            _loadingSteps.Add(codJcom);
            await InvokeAsync(StateHasChanged);

            var jobProgress = await IntegryApiService.RetrieveJobProgress(codJcom);

            if (!token.IsCancellationRequested)
            {
                Steps[codJcom] = jobProgress.Steps;
                await InvokeAsync(StateHasChanged);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Errore nel caricamento step per {codJcom}: {ex.Message}");
            if (!token.IsCancellationRequested)
            {
                Steps[codJcom] = null;
            }
        }
        finally
        {
            _loadingSteps.Remove(codJcom);
            semaphore.Release();
        }
    }

    private bool IsLoadingStep(string codJcom) => _loadingSteps.Contains(codJcom);

    #endregion

    #region UI Methods

    private void SwitchTab(int tabIndex)
    {
        ActiveTab = tabIndex;
        UserState.ActiveTab = ActiveTab;

        if (tabIndex == 1 && Commesse == null)
        {
            _ = Task.Run(async () => await LoadCommesseAsync());
        }
        else if (tabIndex == 1 && Steps.IsNullOrEmpty())
        {
            _ = Task.Run(async () => await LoadStepsForCurrentPageAsync());
        }
        else if (tabIndex == 2 && ActivityList?.Count == 0)
        {
            _ = Task.Run(async () => await LoadActivity());
        }
    }

    private void ApplyFiltersCommesse()
    {
        if (Commesse == null)
        {
            FilteredCommesse = [];
            return;
        }

        var filtered = Commesse.AsEnumerable();
        if (!string.IsNullOrWhiteSpace(SearchTermCommesse))
        {
            var searchLower = SearchTermCommesse.ToLowerInvariant();
            filtered = filtered.Where(c =>
                c.CodJcom?.ToLowerInvariant().Contains(searchLower) == true ||
                c.Descrizione?.ToLowerInvariant().Contains(searchLower) == true ||
                c.CodAnag?.ToLowerInvariant().Contains(searchLower) == true);
        }

        FilteredCommesse = filtered.ToList();
        if (SelectedPageCommesse > TotalPagesCommesse && TotalPagesCommesse > 0) _selectedPageCommesse = 1;

        _ = LoadStepsForCurrentPageAsync();
    }

    private void ApplyFiltersActivity()
    {
        var filtered = ActivityList.AsEnumerable();

        if (!string.IsNullOrWhiteSpace(SearchTermActivity))
        {
            var searchLower = SearchTermActivity.ToLowerInvariant();
            filtered = filtered.Where(a =>
                a.ActivityDescription?.ToLowerInvariant().Contains(searchLower) == true ||
                a.ActivityId?.ToLowerInvariant().Contains(searchLower) == true);
        }

        FilteredActivity = filtered.ToList();
        if (CurrentPageActivityIndex > TotalPagesActivity && TotalPagesActivity > 0)
        {
            _currentPageActivity = 1;
        }
    }

    private void ClearSearchCommesse()
    {
        SearchTermCommesse = string.Empty;
        ApplyFiltersCommesse();
    }

    private void ClearSearchActivity()
    {
        SearchTermActivity = string.Empty;
        ApplyFiltersActivity();
    }

    #endregion

    #region Modal Methods

    private async Task OpenPersRifForm()
    {
        var result = await ModalHelpers.OpenPersRifForm(Dialog, null, Anag, PersRif);

        if (result is { Canceled: false, Data: not null } && result.Data.GetType() == typeof(PersRifDTO))
        {
            await LoadPersRifAsync();
            UserState.PersRif = PersRif;
        }
    }

    private async Task OpenUserForm(ContactDTO anag)
    {
        var result = await ModalHelpers.OpenUserForm(Dialog, anag);

        if (result is { Canceled: false, Data: not null } && result.Data.GetType() == typeof(AnagClie))
        {
            var clie = (AnagClie)result.Data;
            IsContact = true;
            CodContact = clie.CodAnag!;

            await LoadAnagAsync();
            SaveDataToSession();
        }
        else if (result is { Canceled: false })
        {
            await LoadAnagAsync();
            SaveDataToSession();
        }
    }

    #endregion

}