using System.Data;
using Npgsql;
using TravelAgencyWinForms.Data;
using TravelAgencyWinForms.Models;
using TravelAgencyWinForms.Utils;

namespace TravelAgencyWinForms.Forms;

public partial class ReportsForm : Form
{
    private readonly List<Button> _reportButtons = new();
    private DataTable _currentTable = new();

    public ReportsForm()
    {
        InitializeComponent();
        ApplyStyle();
        LoadIllustration();
        RegisterButtons();
        Load += (_, _) => LoadBookingsReport();
    }

    private void ApplyStyle()
    {
        AppTheme.ApplyForm(this);
        headerPanel.BackColor = AppTheme.Surface;
        titleLabel.ForeColor = AppTheme.Text;
        subtitleLabel.ForeColor = AppTheme.Muted;

        AppTheme.StyleGrid(reportGrid);
        AppTheme.StyleSelectedButton(bookingsButton);
        AppTheme.StyleSecondaryButton(scheduleButton);
        AppTheme.StyleSecondaryButton(overdueButton);
        AppTheme.StyleSecondaryButton(employeesButton);

        employeesButton.Visible = CurrentUser.IsAdmin;
    }

    private void LoadIllustration()
    {
        var image = AppTheme.LoadImage("booking_report.png");
        if (image != null)
            reportPictureBox.Image = image;

        var emptyImage = AppTheme.LoadImage("empty_results.png");
        if (emptyImage != null)
            emptyPictureBox.Image = emptyImage;
    }

    private void RegisterButtons()
    {
        _reportButtons.Clear();
        _reportButtons.Add(scheduleButton);
        _reportButtons.Add(bookingsButton);
        _reportButtons.Add(overdueButton);

        if (CurrentUser.IsAdmin)
            _reportButtons.Add(employeesButton);
    }

    private void ScheduleButton_Click(object? sender, EventArgs e)
    {
        SetActiveButton(scheduleButton);
        LoadScheduleReport();
    }

    private void BookingsButton_Click(object? sender, EventArgs e)
    {
        SetActiveButton(bookingsButton);
        LoadBookingsReport();
    }

    private void OverdueButton_Click(object? sender, EventArgs e)
    {
        SetActiveButton(overdueButton);
        LoadOverdueReport();
    }

    private void EmployeesButton_Click(object? sender, EventArgs e)
    {
        SetActiveButton(employeesButton);
        LoadEmployeesReport();
    }

    private void SetActiveButton(Button selectedButton)
    {
        foreach (var button in _reportButtons)
        {
            if (button == selectedButton)
                AppTheme.StyleSelectedButton(button);
            else
                AppTheme.StyleSecondaryButton(button);
        }
    }

    private void LoadScheduleReport()
    {
        titleLabel.Text = "Расписание туров";
        subtitleLabel.Text = "График выездов и длительность поездок";

        BindReport(Db.Query(@"
SELECT
    tour_name AS ""Тур"",
    cities AS ""Города"",
    start_date AS ""Дата начала"",
    end_date AS ""Дата окончания"",
    duration_days AS duration_days,
    price AS ""Стоимость""
FROM v_tour_schedule
ORDER BY start_date, tour_name;"));
    }

    private void LoadBookingsReport()
    {
        titleLabel.Text = CurrentUser.IsAdmin ? "Бронирования" : "Мои бронирования";
        subtitleLabel.Text = CurrentUser.IsAdmin ? "Полный список оформленных бронирований" : "Бронирования, связанные с текущим клиентом";

        var table = CurrentUser.IsAdmin
            ? Db.Query("SELECT * FROM v_booking_details ORDER BY booking_date DESC, booking_id DESC;")
            : Db.Query("SELECT * FROM v_booking_details WHERE client_id = @client_id ORDER BY booking_date DESC, booking_id DESC;", new NpgsqlParameter("client_id", CurrentUser.ClientId ?? -1));

        BindReport(table);
    }

    private void LoadOverdueReport()
    {
        titleLabel.Text = CurrentUser.IsAdmin ? "Просроченные бронирования" : "Мои просроченные бронирования";
        subtitleLabel.Text = "Туры с прошедшей датой начала и незавершённым статусом";

        var table = CurrentUser.IsAdmin
            ? Db.Query("SELECT * FROM v_overdue_client_bookings ORDER BY days_overdue DESC, booking_id DESC;")
            : Db.Query("SELECT * FROM v_overdue_client_bookings WHERE client_id = @client_id ORDER BY days_overdue DESC, booking_id DESC;", new NpgsqlParameter("client_id", CurrentUser.ClientId ?? -1));

        BindReport(table);
    }

    private void LoadEmployeesReport()
    {
        titleLabel.Text = "Сотрудники";
        subtitleLabel.Text = "Возраст и основные сведения по сотрудникам";
        BindReport(Db.Query("SELECT * FROM v_employee_details ORDER BY employee_name;"));
    }

    private void BindReport(DataTable table)
    {
        _currentTable = table;
        reportGrid.DataSource = _currentTable;
        UpdateEmptyState(_currentTable.Rows.Count == 0);
        PresentationHelper.ApplyHeaders(reportGrid);
        PresentationHelper.HideReportColumns(reportGrid);
        HideCalculatedColumns();
        UpdateCalculatedPanel();

        if (reportGrid.Rows.Count > 0 && reportGrid.Columns.Cast<DataGridViewColumn>().Any(c => c.Visible))
        {
            var firstVisible = reportGrid.Columns.Cast<DataGridViewColumn>().First(c => c.Visible);
            reportGrid.CurrentCell = reportGrid.Rows[0].Cells[firstVisible.Index];
        }
    }

    private void UpdateEmptyState(bool isEmpty)
    {
        reportGrid.Visible = !isEmpty;
        emptyPanel.Visible = isEmpty;
    }

    private void HideCalculatedColumns()
    {
        foreach (DataGridViewColumn column in reportGrid.Columns)
            if (CalculatedFields.IsCalculated(column.Name))
                column.Visible = false;
    }

    private void UpdateCalculatedPanel()
    {
        calculatedPanel.Controls.Clear();
        var calculatedColumns = CalculatedFields.GetColumns(_currentTable);

        if (calculatedColumns.Count == 0)
        {
            calculatedPanel.Visible = false;
            return;
        }

        calculatedPanel.Visible = true;
        var selectedRow = GetSelectedRow();

        foreach (var columnName in calculatedColumns)
        {
            var value = "—";
            if (selectedRow != null && selectedRow.Table.Columns.Contains(columnName))
                value = CalculatedFields.FormatValue(columnName, selectedRow[columnName]);

            calculatedPanel.Controls.Add(AppTheme.CreateCard(CalculatedFields.GetLabel(columnName), value));
        }
    }

    private DataRow? GetSelectedRow()
    {
        if (reportGrid.CurrentRow?.DataBoundItem is DataRowView view)
            return view.Row;

        return null;
    }

    private void ReportGrid_SelectionChanged(object? sender, EventArgs e)
    {
        UpdateCalculatedPanel();
    }
}
