using System.ComponentModel.DataAnnotations;
using CafeCritic.Context;
using CafeCritic.Enums;
using CafeCritic.Mappers;
using CafeCritic.Models;
using CafeCritic.Services;
using CafeCritic.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace CafeCritic.Controllers;

public class CafeController : Controller
{
    private readonly CafeDbContext _db;

    private readonly UserManager<User> _userManager;

    public CafeController(CafeDbContext db, UserManager<User> userManager)
    {
        _db = db;
        _userManager = userManager;
    }
    
    [HttpGet]
    public async Task<IActionResult> Index(int page = 1)
    {
        int pageSize = 10;
        IQueryable<Cafe> source = _db.Cafes;
        var count = await source.CountAsync();
        var items = await source.Skip((page - 1) * pageSize).Take(pageSize)
            .Include(c => c.Reviews).ToListAsync();
        PageViewModel pageViewModel = new PageViewModel(count, page, pageSize);
        CafeViewModel viewModel = new CafeViewModel
        {
            PageViewModel = pageViewModel,
            Cafes = items
        };

        return View(viewModel);
    }

    [HttpGet]
    [Authorize]
    public IActionResult AddCafe()
    {
        return View();
    }

    [HttpPost]
    [Authorize]
    [ValidateAntiForgeryToken]
    [Display(Name="AddCafe")]
    public async Task<IActionResult> AddCafeAsync(AddCafeViewModel model)
    {
        if (!ModelState.IsValid) return View(model);
        
        var image = await FileUpload.Upload(model.Title, model.Image);
        var restaurant = CafeMapper.AddCafeCafe(model, image);
        

        await _db.Cafes.AddAsync(restaurant);
        await _db.SaveChangesAsync();

        return RedirectToAction("Index", "Cafe");
    }

    public IActionResult Details(int id)
    {
        var cafe = _db.Cafes
            .Include(c => c.Reviews)
            .FirstOrDefault(c => c.Id == id);
        _db.Reviews.Include(r => r.User)
            .ToList();
        
        if (cafe is not null)
        {
            var viewModel = CafeMapper.CafeCafeDetailViewModel(cafe);
            ViewBag.UserId = _userManager.GetUserId(User);
            ViewBag.Rating = new List<Rating>
            {
                Rating.One,
                Rating.Two,
                Rating.Three,
                Rating.Four,
                Rating.Five
            };
            
            return View(viewModel);
        }

        return NotFound();
    }

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    [Display(Name = "CafeSearch")]
    public async Task<IActionResult> CafeSearchAsync(string search)
    {
        var cafes = await _db.Cafes
            .Where(c => c.Title.Contains(search) || c.Description.Contains(search))
            .ToListAsync();

        var cafeViewModels = cafes.Select(CafeMapper.CafeCafeDetailViewModel).ToList();
        return View(cafeViewModels);
    }
    
    [HttpGet]
    [Authorize]
    [Display(Name = "RemoveReview")]
    public async Task<IActionResult> RemoveReviewAsync(int cafeId)
    {
        var review = await _db.Reviews
            .FirstOrDefaultAsync(r => r.UserId == _userManager.GetUserId(User) && r.CafeId == cafeId);
        if (review is not null)
        {
            _db.Reviews.Remove(review);
            await _db.SaveChangesAsync();
            return RedirectToAction("Details", new { id = cafeId });
        }

        return NotFound();
    }

    [HttpPost]
    [Authorize]
    public async Task<ActionResult> Add([FromForm] AddReviewDto dto)
    {
        var path = await FileUpload.Upload(Guid.NewGuid().ToString(), dto.Photo);

        var cafe = await _db.Cafes.FindAsync(dto.CafeId);
        cafe.Gallery.Add(path);
        await _db.SaveChangesAsync();
        return Ok(new
        {
            success = true
        });
    }
}