using Asp.Versioning;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Mirea.Api.DataAccess.Application.Cqrs.Schedule.Queries.GetScheduleList;
using Mirea.Api.Dto.Requests;
using Mirea.Api.Endpoint.Configuration.Model;
using OfficeOpenXml;
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace Mirea.Api.Endpoint.Controllers.V1;

[ApiVersion("1.0")]
public class ImportController(IMediator mediator, IOptionsSnapshot<GeneralConfig> config) : BaseController
{
    // todo: transfer data to storage
    private static string GetFaculty(char c) =>
        c switch
        {
            'У' => "ИТУ",
            'Б' => "ИКБ",
            'Х' => "ИТХТ",
            'Э' => "ИПТИП",
            'Т' => "ИПТИП",
            'Р' => "ИРИ",
            'К' => "ИИИ",
            'И' => "ИИТ",
            'П' => "ИИТ",
            _ => throw new ArgumentOutOfRangeException(nameof(c), c, null)
        };

    /// <summary>
    /// Creates an Excel file based on a schedule filter
    /// </summary>
    /// <param name="request">The request object containing filter criteria.</param>
    /// <returns>Excel file</returns>
    [HttpPost("ImportToExcel")]
    [Produces("application/vnd.ms-excel")]
    public async Task<FileStreamResult> ImportToExcel([FromBody] ScheduleRequest request)
    {
        var result = (await mediator.Send(new GetScheduleListQuery
        {
            IsEven = request.IsEven,
            DisciplineIds = request.Disciplines,
            GroupIds = request.Groups,
            LectureHallIds = request.LectureHalls,
            ProfessorIds = request.Professors,
            LessonTypeIds = request.LessonType
        })).Schedules.ToList();

        ExcelPackage.License.SetNonCommercialOrganization("Winsomnia");
        using var package = new ExcelPackage();
        var worksheet = package.Workbook.Worksheets.Add("Расписание");

        var row = 1;
        var col = 1;

        worksheet.Cells[row, col++].Value = "День";
        worksheet.Cells[row, col++].Value = "Пара";
        worksheet.Cells[row, col++].Value = "Неделя";
        worksheet.Cells[row, col++].Value = "Время";
        worksheet.Cells[row, col++].Value = "Группа";
        worksheet.Cells[row, col++].Value = "Институт";
        worksheet.Cells[row, col++].Value = "Курс";
        worksheet.Cells[row, col++].Value = "Дисциплина";
        worksheet.Cells[row, col++].Value = "Преподаватель";
        worksheet.Cells[row, col++].Value = "Вид";
        worksheet.Cells[row, col++].Value = "Кампус";
        worksheet.Cells[row, col].Value = "Ауд.";

        row++;
        col = 1;

        var pairsDictionary = config.Value.ScheduleSettings!.PairPeriod;

        var ruCulture = new CultureInfo("ru-RU");

        foreach (var dto in result.GroupBy(s => new
        {
            s.DayOfWeek,
            s.PairNumber,
            s.IsEven,
            s.DisciplineId,
            TypeOfOccupations = string.Join(',', s.TypeOfOccupations.OrderBy(x => x)),
            LectureHalls = string.Join(',', s.LectureHalls.OrderBy(x => x)),
            Campus = string.Join(',', s.Campus.OrderBy(x => x)),
            Professors = string.Join(',', s.Professors.OrderBy(x => x))
        })
                     .Select(g => new
                     {
                         g.Key.DayOfWeek,
                         g.Key.PairNumber,
                         g.Key.IsEven,
                         g.First().Discipline,
                         g.First().LectureHalls,
                         g.First().Campus,
                         g.First().Professors,
                         Groups = string.Join('\n', g.Select(x => x.Group)),

                         IsExclude = g.First().IsExcludedWeeks,
                         g.First().TypeOfOccupations,
                         g.First().Weeks
                     })
                     .ToList())
        {
            // День
            worksheet.Cells[row, col++].Value =
                $"{(int)dto.DayOfWeek} [{ruCulture.DateTimeFormat.GetAbbreviatedDayName(dto.DayOfWeek).ToUpper()}]";

            // Пара
            worksheet.Cells[row, col++].Value = dto.PairNumber + " п";

            // Неделя
            worksheet.Cells[row, col++].Value = $"[{(dto.IsEven ? 2 : 1)}] {(dto.IsEven ? "Четная" : "Нечетная")}";

            // Время
            worksheet.Cells[row, col++].Value = pairsDictionary[dto.PairNumber].Start.ToString(ruCulture);

            // Группа
            worksheet.Cells[row, col].Style.WrapText = true;
            worksheet.Cells[row, col++].Value = dto.Groups;

            var groupTemplate = dto.Groups.Split('\n')[0];

            // Институт
            worksheet.Cells[row, col++].Value = GetFaculty(groupTemplate[0]);
            // Курс
            worksheet.Cells[row, col++].Value = groupTemplate[2] == 'М' ?
                'М' :
                (24 - int.Parse(groupTemplate.Split(' ')[0].Split('-').TakeLast(1).ElementAt(0)) + 1).ToString();

            var disciplineAdditional = string.Empty;

            if (dto.IsExclude.HasValue && dto.Weeks != null && dto.Weeks.Any())
                disciplineAdditional += $"{(dto.IsExclude.Value ? "Кр. " : "")}{string.Join(", ", dto.Weeks.OrderBy(x => x))} н. ";

            // Дисциплина
            worksheet.Cells[row, col++].Value = disciplineAdditional + dto.Discipline;

            // Преподаватель
            worksheet.Cells[row, col++].Value = dto.Professors;
            // Вид
            worksheet.Cells[row, col++].Value = dto.TypeOfOccupations.FirstOrDefault();
            // Кампус
            worksheet.Cells[row, col++].Value = dto.Campus.FirstOrDefault()?.Replace("С-20", "С20").Replace("В-78", "В78");
            // Ауд.
            worksheet.Cells[row, col].Value = dto.LectureHalls;

            col = 1;
            row++;
        }

        worksheet.Cells[1, 1, 1, 12].AutoFilter = true;
        worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();

        var stream = new MemoryStream();
        await package.SaveAsAsync(stream);
        stream.Position = 0;
        return File(stream, "application/vnd.ms-excel", "data.xlsx");
    }
}