using System.Security.Claims;
using Lab12.Authorization;
using Lab12.Mappings;
using Lab12.Models;
using Lab12.Services;
using Lab12.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace Lab12.Controllers;

public class ArticlesController : Controller
{
    private readonly IArticleService _articleService;
    private readonly ICategoryService _categoryService;
    private readonly ITagService _tagService;
    private readonly IWebHostEnvironment _env;

    private const int PageSize = 5;

    public ArticlesController(
        IArticleService articleService,
        ICategoryService categoryService,
        ITagService tagService,
        IWebHostEnvironment env)
    {
        _articleService = articleService;
        _categoryService = categoryService;
        _tagService = tagService;
        _env = env;
    }

    // GET: /Articles?page=1 — public
    public async Task<IActionResult> Index(int page = 1, CancellationToken cancellationToken = default)
    {
        var totalArticles = await _articleService.CountAsync(cancellationToken);
        var totalPages = (int)Math.Ceiling(totalArticles / (double)PageSize);

        if (page < 1) page = 1;
        if (page > totalPages && totalPages > 0) page = totalPages;

        var articles = await _articleService.GetPagedAsync(page, PageSize, cancellationToken);

        ViewBag.CurrentPage = page;
        ViewBag.TotalPages = totalPages;

        return View(articles.ToViewModelList());
    }

    // GET: /Articles/Details/5 — public
    public async Task<IActionResult> Details(int? id, CancellationToken cancellationToken)
    {
        if (id == null)
            return NotFound();

        var article = await _articleService.GetByIdAsync(id.Value, cancellationToken);
        if (article == null)
            return NotFound();

        return View(article.ToViewModel());
    }

    // GET: /Articles/Create — necesită autentificare
    [Authorize]
    public async Task<IActionResult> Create(CancellationToken cancellationToken)
    {
        var viewModel = new CreateArticleViewModel();
        await LoadDropdownsAsync(viewModel, cancellationToken);
        return View(viewModel);
    }

    // POST: /Articles/Create — necesită autentificare
    [Authorize]
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(CreateArticleViewModel viewModel, CancellationToken cancellationToken)
    {
        if (!ModelState.IsValid)
        {
            await LoadDropdownsAsync(viewModel, cancellationToken);
            return View(viewModel);
        }

        var article = new Article
        {
            Title = viewModel.Title,
            Content = viewModel.Content,
            CategoryId = viewModel.CategoryId,
            AuthorId = User.FindFirstValue(ClaimTypes.NameIdentifier)
        };

        if (viewModel.Upload != null)
        {
            var fileName = Path.GetFileName(viewModel.Upload.FileName);
            var savePath = Path.Combine(_env.WebRootPath, "images", fileName);
            using var stream = System.IO.File.Create(savePath);
            await viewModel.Upload.CopyToAsync(stream, cancellationToken);
            article.ImagePath = $"/images/{fileName}";
        }

        await _articleService.AddAsync(article, cancellationToken);

        // Atasare tag-uri Many-to-Many
        if (viewModel.SelectedTagIds.Any())
        {
            var selectedTags = await _tagService.GetByIdsAsync(viewModel.SelectedTagIds, cancellationToken);
            article.Tags = selectedTags;
            await _articleService.UpdateAsync(article, cancellationToken);
        }

        return RedirectToAction(nameof(Index));
    }

    // GET: /Articles/Edit/5 — doar author sau admin
    [Authorize]
    public async Task<IActionResult> Edit(int? id, CancellationToken cancellationToken)
    {
        if (id == null)
            return NotFound();

        var article = await _articleService.GetByIdAsync(id.Value, cancellationToken);
        if (article == null)
            return NotFound();

        if (!User.CanModifyArticle(article))
            return Forbid();

        var viewModel = new EditArticleViewModel
        {
            Id = article.Id,
            Title = article.Title,
            Content = article.Content,
            CategoryId = article.CategoryId,
            ExistingImagePath = article.ImagePath,
            SelectedTagIds = article.Tags?.Select(t => t.Id).ToList() ?? new()
        };

        await LoadDropdownsAsync(viewModel, cancellationToken);
        return View(viewModel);
    }

    // POST: /Articles/Edit/5 — doar author sau admin
    [Authorize]
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(int id, EditArticleViewModel viewModel, CancellationToken cancellationToken)
    {
        if (id != viewModel.Id)
            return NotFound();

        if (!ModelState.IsValid)
        {
            await LoadDropdownsAsync(viewModel, cancellationToken);
            return View(viewModel);
        }

        var article = await _articleService.GetByIdAsync(id, cancellationToken);
        if (article == null)
            return NotFound();

        if (!User.CanModifyArticle(article))
            return Forbid();

        article.Title = viewModel.Title;
        article.Content = viewModel.Content;
        article.CategoryId = viewModel.CategoryId;

        if (viewModel.Upload != null)
        {
            var fileName = Path.GetFileName(viewModel.Upload.FileName);
            var savePath = Path.Combine(_env.WebRootPath, "images", fileName);
            using var stream = System.IO.File.Create(savePath);
            await viewModel.Upload.CopyToAsync(stream, cancellationToken);
            article.ImagePath = $"/images/{fileName}";
        }
        else if (viewModel.ExistingImagePath != null)
        {
            article.ImagePath = viewModel.ExistingImagePath;
        }

        // Re-asociere tag-uri (clear + re-add)
        article.Tags ??= new();
        article.Tags.Clear();
        if (viewModel.SelectedTagIds.Any())
        {
            var selectedTags = await _tagService.GetByIdsAsync(viewModel.SelectedTagIds, cancellationToken);
            foreach (var tag in selectedTags)
                article.Tags.Add(tag);
        }

        await _articleService.UpdateAsync(article, cancellationToken);
        return RedirectToAction(nameof(Index));
    }

    // GET: /Articles/Delete/5 — doar author sau admin
    [Authorize]
    public async Task<IActionResult> Delete(int? id, CancellationToken cancellationToken)
    {
        if (id == null)
            return NotFound();

        var article = await _articleService.GetByIdAsync(id.Value, cancellationToken);
        if (article == null)
            return NotFound();

        if (!User.CanModifyArticle(article))
            return Forbid();

        return View(article.ToViewModel());
    }

    // POST: /Articles/Delete/5 — doar author sau admin
    [Authorize]
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteConfirmed(int id, CancellationToken cancellationToken)
    {
        var article = await _articleService.GetByIdAsync(id, cancellationToken);
        if (article == null)
            return NotFound();

        if (!User.CanModifyArticle(article))
            return Forbid();

        await _articleService.DeleteAsync(id, cancellationToken);
        return RedirectToAction(nameof(Index));
    }

    private async Task LoadDropdownsAsync(CreateArticleViewModel viewModel, CancellationToken cancellationToken)
    {
        var categories = await _categoryService.GetAllAsync(cancellationToken);
        viewModel.Categories = categories
            .Select(c => new SelectListItem { Value = c.Id.ToString(), Text = c.Name })
            .ToList();
        viewModel.AvailableTags = await _tagService.GetAllAsync(cancellationToken);
    }
}
