using Microsoft.AspNetCore.Components.Authorization;
using Raven.Client.Documents;
using ZahlenAnalyse.Web.Models;
using ExcelDataReader;
using System.Data;

namespace ZahlenAnalyse.Web.Services;

public class WorkspaceService
{
    private readonly IDocumentStore _store;
    private readonly AuthenticationStateProvider _authStateProvider;

    // Den AuthStateProvider injizieren
    public WorkspaceService(IDocumentStore store, AuthenticationStateProvider authStateProvider)
    {
        _store = store;
        _authStateProvider = authStateProvider;
    }

    private async Task<string> GetUserIdAsync()
    {
        var authState = await _authStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;
        var userid = user.FindFirst(c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")?.Value 
                      ?? user.FindFirst("sub")?.Value 
                      ?? string.Empty;
        return userid;
    }

    // --- Die Magie passiert hier ---
    private async Task EnrichWithAuditDataAsync(object entity)
    {
        // Wenn das Objekt weder IOwnedEntity noch IAuditableEntity ist, können wir abbrechen
        if (entity is not IOwnedEntity and not IAuditableEntity)
            return;

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

        if (entity is IOwnedEntity ownedEntity)
        {
            var userid = await GetUserIdAsync();

            // Setzt bei JEDEM Speichern sicherheitshalber den aktuellen User als Owner
            ownedEntity.OwnerId = userid;
        }

        if (entity is IAuditableEntity auditableEntity)
        {
            // WICHTIG: Wir setzen CreatedBy und CreatedAt NUR, wenn sie noch leer sind.
            // Sonst würden wir bei einem Update (z.B. Namensänderung des Workspaces) 
            // das ursprüngliche Erstellungsdatum und den ursprünglichen Ersteller überschreiben!
            if (string.IsNullOrWhiteSpace(auditableEntity.CreatedBy))
            {
                auditableEntity.CreatedBy = user.FindFirst("name")?.Value ?? user.Identity?.Name ?? "Unbekannt";
                auditableEntity.CreatedAt = DateTime.UtcNow;
            }
        }
    }

    public async Task SaveWorkspaceAsync(Workspace workspace)
    {
        // 1. Audit-Daten automatisch befüllen
        await EnrichWithAuditDataAsync(workspace);

        // 2. Speichern
        using var session = _store.OpenAsyncSession();
        await session.StoreAsync(workspace);
        await session.SaveChangesAsync(); 
    }

    public async Task<List<Workspace>> GetWorkspacesForUserAsync()
    {

        var authState = await _authStateProvider.GetAuthenticationStateAsync();
        var ownerId = await GetUserIdAsync();

        using var session = _store.OpenAsyncSession();
        return await session.Query<Workspace>()
            .Where(w => w.OwnerId == ownerId)
            .ToListAsync();
    }

    public async Task<Workspace?> GetWorkspaceAsync(string id)
    {
        var authState = await _authStateProvider.GetAuthenticationStateAsync();
        var currentUserId = await GetUserIdAsync();

        using var session = _store.OpenAsyncSession();
        var workspace = await session.LoadAsync<Workspace>(id);


        if (workspace != null && workspace.OwnerId != currentUserId)
        {
            return null; 
        }

        return workspace;
    }

    public async Task SaveFaktAsync(AnalysisFakt fakt)
    {
        // Unsere elegante Hilfsmethode von vorhin füllt OwnerId, CreatedBy und CreatedAt!
        await EnrichWithAuditDataAsync(fakt);

        using var session = _store.OpenAsyncSession();
        await session.StoreAsync(fakt);
        await session.SaveChangesAsync(); 
    }

    public async Task<List<AnalysisFakt>> GetFaktenForWorkspaceAsync(string workspaceId)
    {
        using var session = _store.OpenAsyncSession();
        var ownerId = await GetUserIdAsync();

        
        return await session.Query<AnalysisFakt>()
            .Where(f => f.WorkspaceId == workspaceId && f.OwnerId == ownerId)
            .OrderByDescending(f => f.Date)
            .ToListAsync();
    }

    public async Task ImportFromExcelAsync(string workspaceId, Stream fileStream)
{
    // Encoding für deutsche Excel-Dateien
    System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

    using var reader = ExcelReaderFactory.CreateReader(fileStream);
    var result = reader.AsDataSet(new ExcelDataSetConfiguration() {
        ConfigureDataTable = (_) => new ExcelDataTableConfiguration() { UseHeaderRow = true }
    });

    var dataTable = result.Tables[0];
    
    using var session = _store.OpenAsyncSession();
    
    foreach (DataRow row in dataTable.Rows)
    {
        var fakt = new AnalysisFakt
        {
            WorkspaceId = workspaceId,
            Date = Convert.ToDateTime(row["Datum"]),
            Amount = Convert.ToDecimal(row["Betrag"]),
            // Hier mappen wir dynamisch die Dimensionen
            Dimensions = new Dictionary<string, string>()
        };

        // Wir gehen davon aus, dass deine Excel-Spaltennamen 
        // den Dimensions-Namen entsprechen
        foreach (var col in dataTable.Columns.Cast<DataColumn>().Skip(2)) // Datum/Betrag überspringen
        {
            fakt.Dimensions[col.ColumnName] = row[col.ColumnName].ToString() ?? "";
        }

        await EnrichWithAuditDataAsync(fakt);
        await session.StoreAsync(fakt);
    }
    
    await session.SaveChangesAsync();
}
}