using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using NoticeBoard.Data;
using Ical.Net;
using Ical.Net.CalendarComponents;
using Ical.Net.DataTypes;

namespace NoticeBoard.Controllers;

[Authorize]
public class ApiController : Controller
{
    private readonly IWebHostEnvironment _env;
    private readonly IConfiguration _config;
    private readonly IHttpClientFactory _httpClientFactory;

    public ApiController(IWebHostEnvironment env, IConfiguration config, IHttpClientFactory httpClientFactory)
    {
        _env = env;
        _config = config;
        _httpClientFactory = httpClientFactory;
    }

    [HttpPost]
    public async Task<IActionResult> Upload(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest(new { error = "No file provided." });

        var maxSize = _config.GetValue<int>("MaxUploadSizeMB", 20) * 1024 * 1024;
        if (file.Length > maxSize)
            return BadRequest(new { error = $"File too large. Maximum {maxSize / 1024 / 1024}MB." });

        var allowedExts = new[] { ".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".bmp", ".ico" };
        var ext = Path.GetExtension(file.FileName).ToLower();
        if (!allowedExts.Contains(ext))
            return BadRequest(new { error = "File type not allowed. Use: " + string.Join(", ", allowedExts) });

        var uploadsPath = Path.Combine(_env.WebRootPath, "uploads");
        if (!Directory.Exists(uploadsPath))
            Directory.CreateDirectory(uploadsPath);

        var fileName = $"{DateTime.UtcNow:yyyyMMdd_HHmmss}_{Guid.NewGuid():N}{ext}";
        var filePath = Path.Combine(uploadsPath, fileName);

        using (var stream = new FileStream(filePath, FileMode.Create))
        {
            await file.CopyToAsync(stream);
        }

        return Json(new { location = $"/uploads/{fileName}" });
    }

    [HttpPost]
    public async Task<IActionResult> UploadFile(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest(new { error = "No file provided." });

        var uploadsPath = Path.Combine(_env.WebRootPath, "uploads");
        if (!Directory.Exists(uploadsPath))
            Directory.CreateDirectory(uploadsPath);

        var ext = Path.GetExtension(file.FileName).ToLower();
        var fileName = $"{DateTime.UtcNow:yyyyMMdd_HHmmss}_{Guid.NewGuid():N}{ext}";
        var filePath = Path.Combine(uploadsPath, fileName);

        using (var stream = new FileStream(filePath, FileMode.Create))
        {
            await file.CopyToAsync(stream);
        }

        return Json(new { url = $"/uploads/{fileName}", name = file.FileName, size = file.Length });
    }

    [HttpGet]
    public IActionResult ListUploads()
    {
        var uploadsPath = Path.Combine(_env.WebRootPath, "uploads");
        if (!Directory.Exists(uploadsPath))
            return Json(new { files = Array.Empty<object>() });

        var imageExts = new[] { ".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".bmp", ".ico" };
        var files = Directory.GetFiles(uploadsPath)
            .Select(f => new FileInfo(f))
            .Where(f => imageExts.Contains(f.Extension.ToLower()))
            .OrderByDescending(f => f.CreationTimeUtc)
            .Select(f => new
            {
                title = f.Name,
                value = $"/uploads/{f.Name}"
            });

        return Json(files);
    }

    [HttpPost]
    public IActionResult DeleteUpload([FromBody] DeleteFileRequest request)
    {
        if (string.IsNullOrEmpty(request?.FileName))
            return BadRequest();

        var filePath = Path.Combine(_env.WebRootPath, "uploads", Path.GetFileName(request.FileName));
        if (System.IO.File.Exists(filePath))
        {
            System.IO.File.Delete(filePath);
            return Ok();
        }
        return NotFound();
    }

    [AllowAnonymous]
    [HttpGet]
    public async Task<IActionResult> ParseIcs(string url)
    {
        if (string.IsNullOrWhiteSpace(url))
            return BadRequest(new { error = "No URL provided." });

        try
        {
            string icsContent;

            if (url.StartsWith("/uploads/"))
            {
                var filePath = Path.Combine(_env.WebRootPath, url.TrimStart('/'));
                if (!System.IO.File.Exists(filePath))
                    return NotFound(new { error = "ICS file not found." });
                icsContent = await System.IO.File.ReadAllTextAsync(filePath);
            }
            else
            {
                var client = _httpClientFactory.CreateClient();
                client.Timeout = TimeSpan.FromSeconds(15);
                icsContent = await client.GetStringAsync(url);
            }

            var calendar = Calendar.Load(icsContent);
            var now = DateTime.Now;
            var upcoming = calendar.Events
                .Where(e => e.DtEnd != null ? e.DtEnd.AsSystemLocal >= now : e.DtStart.AsSystemLocal >= now.AddDays(-1))
                .OrderBy(e => e.DtStart.AsSystemLocal)
                .Take(20)
                .Select(e => new
                {
                    summary = e.Summary,
                    description = e.Description,
                    location = e.Location,
                    start = e.DtStart?.AsSystemLocal.ToString("yyyy-MM-dd HH:mm"),
                    end = e.DtEnd?.AsSystemLocal.ToString("yyyy-MM-dd HH:mm"),
                    allDay = e.IsAllDay
                });

            return Json(new { events = upcoming });
        }
        catch (Exception ex)
        {
            return BadRequest(new { error = $"Failed to parse ICS: {ex.Message}" });
        }
    }
}

public class DeleteFileRequest
{
    public string? FileName { get; set; }
}
