using ClosedXML.Excel;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using timetracker.Shared;

namespace timetracker.Data;

public static class ExcelExporter
{
    public static async Task<byte[]> GenerateExcelExportAsync(
        int userId,
        DateOnly startDate,
        DateOnly endDate,
        string title,
        ITimetrackerService trackerService,
        TimetrackerDbContext db)
    {
        var settings = await trackerService.GetSettingsAsync(userId);

        var workDays = await db.WorkDays
            .Include(w => w.Breaks)
            .Where(w => w.UserId == userId && w.Date >= startDate && w.Date <= endDate)
            .ToDictionaryAsync(w => w.Date);

        var holidaysList = await db.PublicHolidays
            .Where(h => h.Date >= startDate && h.Date <= endDate)
            .ToListAsync();

        var state = settings.GermanState;
        var holidayMap = holidaysList
            .Where(h => string.IsNullOrEmpty(h.Counties) || (!string.IsNullOrEmpty(state) && h.Counties.Split(',').Contains(state)))
            .ToDictionary(h => h.Date, h => h.Name);

        var vacationMap = await db.VacationDays
            .Where(v => v.UserId == userId && v.Date >= startDate && v.Date <= endDate)
            .ToDictionaryAsync(v => v.Date, v => v.Note ?? "Urlaub");

        var user = await db.Users.FindAsync(userId);
        var userName = user != null ? user.Username : "Mitarbeiter";

        var rows = new List<ExportRow>();

        for (var date = startDate; date <= endDate; date = date.AddDays(1))
        {
            bool isWorkDay = settings.IsWorkDay(date.DayOfWeek);
            bool isHoliday = holidayMap.ContainsKey(date);
            bool isVacation = vacationMap.ContainsKey(date);

            double targetHours = (isWorkDay && !isHoliday && !isVacation) ? settings.DailyTargetHours : 0.0;

            string status = "Wochenende";
            if (isHoliday) status = "Feiertag";
            else if (isVacation) status = "Urlaub";
            else if (isWorkDay) status = "Arbeitstag";

            TimeSpan? startTime = null;
            TimeSpan? endTime = null;
            TimeSpan breakTime = TimeSpan.Zero;
            double actualHours = 0.0;

            string note = "";
            if (isHoliday) note = holidayMap[date];
            else if (isVacation) note = vacationMap[date];

            if (workDays.TryGetValue(date, out var wd))
            {
                if (wd.StartTime.HasValue) startTime = wd.StartTime.Value.ToTimeSpan();
                if (wd.EndTime.HasValue) endTime = wd.EndTime.Value.ToTimeSpan();

                if (startTime.HasValue && endTime.HasValue)
                {
                    var gross = endTime.Value - startTime.Value;
                    if (gross > TimeSpan.Zero)
                    {
                        var breakTotal = wd.Breaks
                            .Where(b => b.StartTime.HasValue && b.EndTime.HasValue && b.EndTime > b.StartTime)
                            .Aggregate(TimeSpan.Zero, (s, b) =>
                                s + (b.EndTime!.Value.ToTimeSpan() - b.StartTime!.Value.ToTimeSpan()));

                        var minMinutes = gross.TotalHours >= 9.0 ? 45 : 30;
                        var minBreak = TimeSpan.FromMinutes(Math.Max(minMinutes, settings.MinimumBreakMinutes));
                        var finalBreak = breakTotal > minBreak ? breakTotal : minBreak;

                        breakTime = finalBreak;
                        actualHours = (gross - finalBreak).TotalHours;
                        if (actualHours < 0) actualHours = 0.0;
                    }
                }
            }

            rows.Add(new ExportRow
            {
                Date = date,
                Status = status,
                StartTime = startTime,
                EndTime = endTime,
                BreakTime = breakTime,
                ActualHours = actualHours,
                TargetHours = targetHours,
                DiffHours = actualHours - targetHours,
                Note = note
            });
        }

        return ExportToExcel(title, userName, startDate, endDate, rows);
    }

    public static byte[] ExportToExcel(
        string title,
        string userName,
        DateOnly startDate,
        DateOnly endDate,
        List<ExportRow> rows)
    {
        using var workbook = new XLWorkbook();
        var worksheet = workbook.Worksheets.Add("Arbeitszeiten");

        // Gitterlinien explizit einblenden
        worksheet.ShowGridLines = true;

        // Title Block
        worksheet.Cell("A1").Value = title;
        worksheet.Cell("A1").Style.Font.Bold = true;
        worksheet.Cell("A1").Style.Font.FontSize = 16;
        worksheet.Cell("A1").Style.Font.FontColor = XLColor.FromHtml("#0F172A"); // Slate 900

        // Info Block
        worksheet.Cell("A2").Value = $"Mitarbeiter: {userName}";
        worksheet.Cell("A2").Style.Font.FontSize = 11;
        worksheet.Cell("A2").Style.Font.Italic = true;

        worksheet.Cell("A3").Value = $"Zeitraum: {startDate:dd.MM.yyyy} bis {endDate:dd.MM.yyyy}";
        worksheet.Cell("A3").Style.Font.FontSize = 11;
        worksheet.Cell("A3").Style.Font.Italic = true;

        // Tabellenüberschriften (Zeile 5)
        string[] headers = {
            "Datum", "Wochentag", "Status", "Beginn", "Ende",
            "Pause", "Netto (Ist)", "Soll-Stunden", "Differenz (Gleitzeit)", "Notiz / Feiertag / Urlaub"
        };

        for (int i = 0; i < headers.Length; i++)
        {
            var cell = worksheet.Cell(5, i + 1);
            cell.Value = headers[i];
            cell.Style.Font.Bold = true;
            cell.Style.Font.FontColor = XLColor.White;
            cell.Style.Fill.BackgroundColor = XLColor.FromHtml("#0EA5E9"); // Primary color (Sky 500)
            cell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
        }

        // Datenzeilen
        int currentRow = 6;
        var deCulture = new CultureInfo("de-DE");
        foreach (var r in rows)
        {
            worksheet.Cell(currentRow, 1).Value = r.Date.ToString("dd.MM.yyyy");
            worksheet.Cell(currentRow, 2).Value = r.Date.ToString("dddd", deCulture);
            worksheet.Cell(currentRow, 3).Value = r.Status;

            if (r.StartTime.HasValue)
            {
                worksheet.Cell(currentRow, 4).Value = r.StartTime.Value.ToString(@"hh\:mm");
            }
            else
            {
                worksheet.Cell(currentRow, 4).Value = "—";
            }

            if (r.EndTime.HasValue)
            {
                worksheet.Cell(currentRow, 5).Value = r.EndTime.Value.ToString(@"hh\:mm");
            }
            else
            {
                worksheet.Cell(currentRow, 5).Value = "—";
            }

            worksheet.Cell(currentRow, 6).Value = r.BreakTime.TotalMinutes > 0 ? r.BreakTime.ToString(@"hh\:mm") : "—";

            worksheet.Cell(currentRow, 7).Value = r.ActualHours;
            worksheet.Cell(currentRow, 7).Style.NumberFormat.Format = "0.00";

            worksheet.Cell(currentRow, 8).Value = r.TargetHours;
            worksheet.Cell(currentRow, 8).Style.NumberFormat.Format = "0.00";

            worksheet.Cell(currentRow, 9).Value = r.DiffHours;
            worksheet.Cell(currentRow, 9).Style.NumberFormat.Format = "+0.00;-0.00;0.00";

            if (r.DiffHours > 0)
            {
                worksheet.Cell(currentRow, 9).Style.Font.FontColor = XLColor.FromHtml("#16A34A"); // Green 600
                worksheet.Cell(currentRow, 9).Style.Font.Bold = true;
            }
            else if (r.DiffHours < 0)
            {
                worksheet.Cell(currentRow, 9).Style.Font.FontColor = XLColor.FromHtml("#DC2626"); // Red 600
                worksheet.Cell(currentRow, 9).Style.Font.Bold = true;
            }

            worksheet.Cell(currentRow, 10).Value = r.Note;

            // Zebra-Streifen
            if (currentRow % 2 == 0)
            {
                for (int col = 1; col <= headers.Length; col++)
                {
                    worksheet.Cell(currentRow, col).Style.Fill.BackgroundColor = XLColor.FromHtml("#F8FAFC"); // Slate 50
                }
            }

            // Rahmenlinien
            for (int col = 1; col <= headers.Length; col++)
            {
                worksheet.Cell(currentRow, col).Style.Border.BottomBorder = XLBorderStyleValues.Thin;
                worksheet.Cell(currentRow, col).Style.Border.BottomBorderColor = XLColor.FromHtml("#E2E8F0");
            }

            currentRow++;
        }

        // Summenzeile
        currentRow++;

        worksheet.Cell(currentRow, 6).Value = "Gesamt:";
        worksheet.Cell(currentRow, 6).Style.Font.Bold = true;
        worksheet.Cell(currentRow, 6).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Right;

        var actualSumRange = $"G6:G{currentRow - 2}";
        worksheet.Cell(currentRow, 7).FormulaA1 = $"SUM({actualSumRange})";
        worksheet.Cell(currentRow, 7).Style.Font.Bold = true;
        worksheet.Cell(currentRow, 7).Style.NumberFormat.Format = "0.00";

        var targetSumRange = $"H6:H{currentRow - 2}";
        worksheet.Cell(currentRow, 8).FormulaA1 = $"SUM({targetSumRange})";
        worksheet.Cell(currentRow, 8).Style.Font.Bold = true;
        worksheet.Cell(currentRow, 8).Style.NumberFormat.Format = "0.00";

        var diffSumRange = $"I6:I{currentRow - 2}";
        worksheet.Cell(currentRow, 9).FormulaA1 = $"SUM({diffSumRange})";
        worksheet.Cell(currentRow, 9).Style.Font.Bold = true;
        worksheet.Cell(currentRow, 9).Style.NumberFormat.Format = "+0.00;-0.00;0.00";

        // Summenrahmen
        for (int col = 6; col <= 9; col++)
        {
            worksheet.Cell(currentRow, col).Style.Border.TopBorder = XLBorderStyleValues.Thin;
            worksheet.Cell(currentRow, col).Style.Border.TopBorderColor = XLColor.Black;
            worksheet.Cell(currentRow, col).Style.Border.BottomBorder = XLBorderStyleValues.Double;
            worksheet.Cell(currentRow, col).Style.Border.BottomBorderColor = XLColor.Black;
        }

        // Spaltenbreiten automatisch anpassen
        worksheet.Columns().AdjustToContents();

        using var memoryStream = new MemoryStream();
        workbook.SaveAs(memoryStream);
        return memoryStream.ToArray();
    }
}

public class ExportRow
{
    public DateOnly Date { get; set; }
    public string Status { get; set; } = "";
    public TimeSpan? StartTime { get; set; }
    public TimeSpan? EndTime { get; set; }
    public TimeSpan BreakTime { get; set; }
    public double ActualHours { get; set; }
    public double TargetHours { get; set; }
    public double DiffHours { get; set; }
    public string Note { get; set; } = "";
}
