using System.Collections.ObjectModel;
using ClaudeDo.Data;
using ClaudeDo.Data.Models;
using ClaudeDo.Data.Repositories;
using ClaudeDo.Ui.Localization;
using ClaudeDo.Ui.Services;
using ClaudeDo.Ui.ViewModels.Agent;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.EntityFrameworkCore;

namespace ClaudeDo.Ui.ViewModels.Modals;

public sealed partial class ListSettingsModalViewModel : ViewModelBase
{
    private readonly IWorkerClient _worker;
    private readonly IDbContextFactory<ClaudeDoDbContext> _dbFactory;

    public string ListId { get; set; } = "";

    // True after the list was deleted, so the caller reloads the list nav instead of refreshing the row.
    public bool Deleted { get; private set; }

    // Wired by the view to prompt yes/no before deleting and to surface a blocking-FK error.
    public Func<string, Task<bool>>? ConfirmAsync { get; set; }
    public Func<string, Task>? ShowErrorAsync { get; set; }

    [ObservableProperty] private string _name = "";
    [ObservableProperty] private string _workingDir = "";
    [ObservableProperty] private string _defaultCommitType = CommitTypeRegistry.DefaultType;

    public ObservableCollection<string> CommitTypeOptions { get; } = new(CommitTypeRegistry.Types);

    // The shared agent-config editor (Model / MaxTurns / SystemPrompt / AgentFile),
    // scoped to this list (list → global inheritance).
    public AgentConfigEditorViewModel Agent { get; }

    public Action? CloseAction { get; set; }

    public ListSettingsModalViewModel(IWorkerClient worker, IDbContextFactory<ClaudeDoDbContext> dbFactory)
    {
        _worker = worker;
        _dbFactory = dbFactory;
        Agent = new AgentConfigEditorViewModel(worker, AgentConfigScope.List);
    }

    public async Task LoadAsync(
        string listId,
        string name,
        string? workingDir,
        string defaultCommitType,
        CancellationToken ct = default)
    {
        ListId = listId;
        Name = name;
        WorkingDir = workingDir ?? "";
        DefaultCommitType = string.IsNullOrWhiteSpace(defaultCommitType) ? CommitTypeRegistry.DefaultType : defaultCommitType;

        await Agent.LoadForListAsync(listId, ct);
    }

    [RelayCommand]
    private async Task SaveAsync()
    {
        await _worker.UpdateListAsync(new UpdateListDto(
            ListId,
            string.IsNullOrWhiteSpace(Name) ? Loc.T("vm.listSettings.untitled") : Name,
            string.IsNullOrWhiteSpace(WorkingDir) ? null : WorkingDir,
            DefaultCommitType));

        await Agent.SaveAsync();

        CloseAction?.Invoke();
    }

    [RelayCommand]
    private async Task DeleteAsync()
    {
        var displayName = string.IsNullOrWhiteSpace(Name) ? Loc.T("vm.listSettings.untitled") : Name;
        if (ConfirmAsync is not null)
        {
            var ok = await ConfirmAsync($"Delete list \"{displayName}\" and all its tasks? This cannot be undone.");
            if (!ok) return;
        }

        try
        {
            await using var ctx = await _dbFactory.CreateDbContextAsync();
            var lists = new ListRepository(ctx);
            await lists.DeleteAsync(ListId);
        }
        catch (Exception ex) when (
            (ex is Microsoft.Data.Sqlite.SqliteException
                || ex.InnerException is Microsoft.Data.Sqlite.SqliteException)
            && (ex.Message.Contains("FOREIGN KEY", StringComparison.OrdinalIgnoreCase)
                || ex.InnerException?.Message.Contains("FOREIGN KEY", StringComparison.OrdinalIgnoreCase) == true))
        {
            if (ShowErrorAsync is not null)
                await ShowErrorAsync("This list has planning sessions with child tasks. Discard those first, then delete the list.");
            return;
        }

        Deleted = true;
        CloseAction?.Invoke();
    }

    [RelayCommand]
    private void Cancel() => CloseAction?.Invoke();
}
