using LEA.Data;
using LEA.Extensions;
using LEA.Models;
using LEA.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;

namespace LEA.Controllers;

[Authorize]
public class ApplicationsController : Controller
{
    private readonly AppDbContext _context;
    private readonly UserManager<ApplicationUser> _userManager;

    public ApplicationsController(AppDbContext context, UserManager<ApplicationUser> userManager)
    {
        _context = context;
        _userManager = userManager;
    }

    public async Task<IActionResult> Index(string? searchTerm, ApplicationStatus? status)
    {
        var userId = GetCurrentUserId();
        var query = _context.Applications
            .Include(a => a.Contact)
            .Where(a => a.UserId == userId);

        if (!string.IsNullOrWhiteSpace(searchTerm))
        {
            var term = $"%{searchTerm.Trim()}%";
            query = query.Where(a =>
                EF.Functions.Like(a.Company, term) ||
                EF.Functions.Like(a.Role, term) ||
                EF.Functions.Like(a.Source ?? string.Empty, term) ||
                EF.Functions.Like(a.Notes ?? string.Empty, term) ||
                (a.Contact != null && (
                    EF.Functions.Like(a.Contact.FullName ?? string.Empty, term) ||
                    EF.Functions.Like(a.Contact.Email ?? string.Empty, term))));
        }

        if (status.HasValue)
        {
            query = query.Where(a => a.Status == status.Value);
        }

        var applications = await query
            .OrderByDescending(a => a.UpdatedAt)
            .ThenByDescending(a => a.AppliedOn)
            .ToListAsync();

        var statsQuery = _context.Applications.Where(a => a.UserId == userId);
        var statusCounts = await statsQuery
            .GroupBy(a => a.Status)
            .Select(g => new { g.Key, Count = g.Count() })
            .ToListAsync();

        var statusDictionary = Enum.GetValues<ApplicationStatus>()
            .ToDictionary(s => s, s => statusCounts.FirstOrDefault(sc => sc.Key == s)?.Count ?? 0);

        var model = new ApplicationListViewModel
        {
            Applications = applications,
            SearchTerm = searchTerm,
            StatusFilter = status,
            StatusOptions = GetStatusSelectList(status, includeAllOption: true),
            StatusCounts = statusDictionary,
            TotalApplications = await statsQuery.CountAsync()
        };

        return View(model);
    }

    [HttpGet]
    public IActionResult Create()
    {
        var model = new ApplicationFormViewModel
        {
            AppliedOn = DateTime.Today,
            Status = ApplicationStatus.Applied,
            StatusOptions = GetStatusSelectList(ApplicationStatus.Applied),
            Heading = "Bewerbung hinzufügen",
            SubmitText = "Speichern"
        };

        return View(model);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(ApplicationFormViewModel model)
    {
        if (!ModelState.IsValid)
        {
            model.StatusOptions = GetStatusSelectList(model.Status);
            model.Heading = "Bewerbung hinzufügen";
            model.SubmitText = "Speichern";
            return View(model);
        }

        var application = new Application
        {
            Role = model.Role.Trim(),
            Company = model.Company.Trim(),
            Source = string.IsNullOrWhiteSpace(model.Source) ? null : model.Source.Trim(),
            Status = model.Status,
            AppliedOn = model.AppliedOn,
            Notes = string.IsNullOrWhiteSpace(model.Notes) ? null : model.Notes.Trim(),
            UserId = GetCurrentUserId(),
            UpdatedAt = DateTime.UtcNow
        };

        if (HasContactInformation(model))
        {
            application.Contact = new Contact
            {
                FullName = string.IsNullOrWhiteSpace(model.ContactName) ? null : model.ContactName.Trim(),
                Email = string.IsNullOrWhiteSpace(model.ContactEmail) ? null : model.ContactEmail.Trim(),
                Phone = string.IsNullOrWhiteSpace(model.ContactPhone) ? null : model.ContactPhone.Trim()
            };
        }

        _context.Applications.Add(application);
        await _context.SaveChangesAsync();

        TempData["Success"] = "Die Bewerbung wurde gespeichert.";
        return RedirectToAction(nameof(Index));
    }

    [HttpGet]
    public async Task<IActionResult> Edit(int id)
    {
        var application = await FindApplicationForCurrentUserAsync(id);
        if (application == null)
        {
            return NotFound();
        }

        var model = new ApplicationFormViewModel
        {
            Id = application.Id,
            Role = application.Role,
            Company = application.Company,
            Source = application.Source,
            Status = application.Status,
            AppliedOn = application.AppliedOn,
            Notes = application.Notes,
            ContactName = application.Contact?.FullName,
            ContactEmail = application.Contact?.Email,
            ContactPhone = application.Contact?.Phone,
            StatusOptions = GetStatusSelectList(application.Status),
            Heading = "Bewerbung bearbeiten",
            SubmitText = "Änderungen speichern"
        };

        return View(model);
    }

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

        if (!ModelState.IsValid)
        {
            model.StatusOptions = GetStatusSelectList(model.Status);
            model.Heading = "Bewerbung bearbeiten";
            model.SubmitText = "Änderungen speichern";
            return View(model);
        }

        var application = await FindApplicationForCurrentUserAsync(id);
        if (application == null)
        {
            return NotFound();
        }

        application.Role = model.Role.Trim();
        application.Company = model.Company.Trim();
        application.Source = string.IsNullOrWhiteSpace(model.Source) ? null : model.Source.Trim();
        application.Status = model.Status;
        application.AppliedOn = model.AppliedOn;
        application.Notes = string.IsNullOrWhiteSpace(model.Notes) ? null : model.Notes.Trim();
        application.UpdatedAt = DateTime.UtcNow;

        if (HasContactInformation(model))
        {
            if (application.Contact == null)
            {
                application.Contact = new Contact();
            }

            application.Contact.FullName = string.IsNullOrWhiteSpace(model.ContactName) ? null : model.ContactName.Trim();
            application.Contact.Email = string.IsNullOrWhiteSpace(model.ContactEmail) ? null : model.ContactEmail.Trim();
            application.Contact.Phone = string.IsNullOrWhiteSpace(model.ContactPhone) ? null : model.ContactPhone.Trim();
        }
        else if (application.Contact != null)
        {
            _context.Contacts.Remove(application.Contact);
        }

        await _context.SaveChangesAsync();

        TempData["Success"] = "Die Bewerbung wurde aktualisiert.";
        return RedirectToAction(nameof(Index));
    }

    [HttpGet]
    public async Task<IActionResult> Details(int id)
    {
        var application = await FindApplicationForCurrentUserAsync(id);
        if (application == null)
        {
            return NotFound();
        }

        return View(application);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Delete(int id)
    {
        var application = await FindApplicationForCurrentUserAsync(id);
        if (application == null)
        {
            return NotFound();
        }

        _context.Applications.Remove(application);
        await _context.SaveChangesAsync();

        TempData["Success"] = "Die Bewerbung wurde gelöscht.";
        return RedirectToAction(nameof(Index));
    }

    private async Task<Application?> FindApplicationForCurrentUserAsync(int id)
    {
        var userId = GetCurrentUserId();
        return await _context.Applications
            .Include(a => a.Contact)
            .Where(a => a.UserId == userId)
            .FirstOrDefaultAsync(a => a.Id == id);
    }

    private IEnumerable<SelectListItem> GetStatusSelectList(ApplicationStatus? selectedStatus, bool includeAllOption = false)
    {
        var options = Enum.GetValues<ApplicationStatus>()
            .Select(status => new SelectListItem
            {
                Text = status.GetDisplayName(),
                Value = status.ToString(),
                Selected = selectedStatus.HasValue && selectedStatus.Value == status
            })
            .ToList();

        if (includeAllOption)
        {
            options.Insert(0, new SelectListItem
            {
                Text = "Alle Status",
                Value = string.Empty,
                Selected = !selectedStatus.HasValue
            });
        }

        return options;
    }

    private bool HasContactInformation(ApplicationFormViewModel model)
    {
        return !string.IsNullOrWhiteSpace(model.ContactName)
               || !string.IsNullOrWhiteSpace(model.ContactEmail)
               || !string.IsNullOrWhiteSpace(model.ContactPhone);
    }

    private string GetCurrentUserId()
    {
        return _userManager.GetUserId(User)
               ?? throw new InvalidOperationException("Benutzer ist nicht angemeldet.");
    }
}
