using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NoticeBoard.Data;
using NoticeBoard.Models;

namespace NoticeBoard.Controllers;

[Authorize]
public class DevicesController : Controller
{
    private readonly AppDbContext _db;

    public DevicesController(AppDbContext db)
    {
        _db = db;
    }

    public async Task<IActionResult> Index()
    {
        var devices = await _db.Devices
            .Include(d => d.DeviceSlides)
            .OrderBy(d => d.Name)
            .ToListAsync();
        return View(devices);
    }

    public IActionResult Create()
    {
        return View(new Device());
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(Device device)
    {
        if (string.IsNullOrWhiteSpace(device.Slug))
            device.Slug = device.Name.ToLower().Replace(" ", "").Replace("-", "");

        device.Slug = device.Slug.ToLower().Trim();

        if (await _db.Devices.AnyAsync(d => d.Slug == device.Slug))
        {
            ModelState.AddModelError("Slug", "This slug is already in use.");
            return View(device);
        }

        if (!ModelState.IsValid) return View(device);

        device.CreatedAt = DateTime.UtcNow;
        _db.Devices.Add(device);
        await _db.SaveChangesAsync();

        TempData["Success"] = $"Device '{device.Name}' created. URL: /{device.Slug}";
        return RedirectToAction(nameof(Index));
    }

    public async Task<IActionResult> Edit(int id)
    {
        var device = await _db.Devices.FindAsync(id);
        if (device == null) return NotFound();
        return View(device);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(int id, Device device)
    {
        if (id != device.Id) return NotFound();

        device.Slug = device.Slug.ToLower().Trim();

        if (await _db.Devices.AnyAsync(d => d.Slug == device.Slug && d.Id != id))
        {
            ModelState.AddModelError("Slug", "This slug is already in use.");
            return View(device);
        }

        if (!ModelState.IsValid) return View(device);

        var existing = await _db.Devices.FindAsync(id);
        if (existing == null) return NotFound();

        existing.Name = device.Name;
        existing.Slug = device.Slug;
        existing.ResolutionWidth = device.ResolutionWidth;
        existing.ResolutionHeight = device.ResolutionHeight;
        existing.Transition = device.Transition;

        await _db.SaveChangesAsync();
        TempData["Success"] = $"Device '{device.Name}' updated.";
        return RedirectToAction(nameof(Index));
    }

    public async Task<IActionResult> Delete(int id)
    {
        var device = await _db.Devices
            .Include(d => d.DeviceSlides)
            .FirstOrDefaultAsync(d => d.Id == id);
        if (device == null) return NotFound();
        return View(device);
    }

    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteConfirmed(int id)
    {
        var device = await _db.Devices.FindAsync(id);
        if (device == null) return NotFound();

        _db.Devices.Remove(device);
        await _db.SaveChangesAsync();

        TempData["Success"] = $"Device '{device.Name}' deleted.";
        return RedirectToAction(nameof(Index));
    }

    public async Task<IActionResult> Playlist(int id)
    {
        var device = await _db.Devices
            .Include(d => d.DeviceSlides.OrderBy(ds => ds.DisplayOrder))
                .ThenInclude(ds => ds.Slide)
            .FirstOrDefaultAsync(d => d.Id == id);

        if (device == null) return NotFound();

        var assignedSlideIds = device.DeviceSlides.Select(ds => ds.SlideId).ToHashSet();
        ViewBag.AvailableSlides = await _db.Slides
            .Where(s => !assignedSlideIds.Contains(s.Id))
            .OrderBy(s => s.Name)
            .ToListAsync();

        return View(device);
    }

    [HttpPost]
    public async Task<IActionResult> AddToPlaylist(int id, int slideId, int durationSeconds = 30)
    {
        var device = await _db.Devices.Include(d => d.DeviceSlides).FirstOrDefaultAsync(d => d.Id == id);
        if (device == null) return NotFound();

        var maxOrder = device.DeviceSlides.Any() ? device.DeviceSlides.Max(ds => ds.DisplayOrder) : 0;

        var ds = new DeviceSlide
        {
            DeviceId = id,
            SlideId = slideId,
            DisplayOrder = maxOrder + 1,
            DurationSeconds = durationSeconds,
            Enabled = true
        };

        _db.DeviceSlides.Add(ds);
        await _db.SaveChangesAsync();
        return RedirectToAction(nameof(Playlist), new { id });
    }

    [HttpPost]
    public async Task<IActionResult> RemoveFromPlaylist(int id, int deviceSlideId)
    {
        var ds = await _db.DeviceSlides.FindAsync(deviceSlideId);
        if (ds == null) return NotFound();

        _db.DeviceSlides.Remove(ds);
        await _db.SaveChangesAsync();
        return RedirectToAction(nameof(Playlist), new { id });
    }

    [HttpPost]
    public async Task<IActionResult> ReorderPlaylist([FromBody] ReorderRequest request)
    {
        if (request?.ItemIds == null) return BadRequest();

        var deviceSlides = await _db.DeviceSlides
            .Where(ds => request.ItemIds.Contains(ds.Id))
            .ToListAsync();

        for (int i = 0; i < request.ItemIds.Length; i++)
        {
            var ds = deviceSlides.FirstOrDefault(x => x.Id == request.ItemIds[i]);
            if (ds != null) ds.DisplayOrder = i + 1;
        }

        await _db.SaveChangesAsync();
        return Ok();
    }

    [HttpPost]
    public async Task<IActionResult> UpdateDuration([FromBody] UpdateDurationRequest request)
    {
        var ds = await _db.DeviceSlides.FindAsync(request.DeviceSlideId);
        if (ds == null) return NotFound();
        ds.DurationSeconds = request.DurationSeconds;
        await _db.SaveChangesAsync();
        return Ok();
    }

    [HttpPost]
    public async Task<IActionResult> ToggleEnabled([FromBody] ToggleEnabledRequest request)
    {
        var ds = await _db.DeviceSlides.FindAsync(request.DeviceSlideId);
        if (ds == null) return NotFound();
        ds.Enabled = request.Enabled;
        await _db.SaveChangesAsync();
        return Ok();
    }
}

public class ReorderRequest { public int[]? ItemIds { get; set; } }
public class UpdateDurationRequest { public int DeviceSlideId { get; set; } public int DurationSeconds { get; set; } }
public class ToggleEnabledRequest { public int DeviceSlideId { get; set; } public bool Enabled { get; set; } }
