using System.Diagnostics;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using bitforum.Constants;
using bitforum.Models;
using bitforum.Models.Page.Banner;
using bitforum.Repository;

namespace bitforum.Controllers.Page.Banner
{
    [Authorize]
    [Route("Page")]
    public class PositionController : Controller
    {
        private readonly ILogger<PositionController> _logger;
        private readonly IRedisRepository _redisRepository;
        private readonly DefaultDbContext _db;
        private readonly string _ViewPath = "~/Views/Page/Banner/Position/Index.cshtml";

        public PositionController(ILogger<PositionController> logger, IRedisRepository redisRepository, DefaultDbContext db)
        {
            _logger = logger;
            _redisRepository = redisRepository;
            _db = db;
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }

        [HttpGet("Banner")]
        public IActionResult Index()
        {
            ViewBag.BannerPositions = _db.BannerPosition.Include(c => c.BannerItem).ToList();
            ViewBag.Total = ViewBag.BannerPositions?.Count ?? 0;

            return View(_ViewPath);
        }

        [HttpPost("Banner")]
        public async Task<IActionResult> Save([FromForm] List<BannerPosition> request)
        {
            using var transaction = await _db.Database.BeginTransactionAsync();

            try
            {
                if (request == null || !request.Any())
                {
                    // 전체 삭제
                    var bannerPositions = await _db.BannerPosition.ToListAsync();
                    if (bannerPositions.Any())
                    {
                        _db.BannerPosition.RemoveRange(bannerPositions);
                        await _db.SaveChangesAsync();
                    }

                    await transaction.CommitAsync();
                    return RedirectToAction("Index");
                }

                if (!ModelState.IsValid)
                {
                    throw new Exception("유효성 검사에 실패하였습니다.");
                }
                
                var requestIDs = request.Select(x => x.ID).ToList(); // 요청 데이터의 ID 목록
                var existingIDs = await _db.BannerPosition.Select(c => c.ID).ToListAsync(); // 데이터베이스에 존재하는 ID 목록
                var IDsToDelete = existingIDs.Except(requestIDs).ToList(); // 삭제 대상 ID: 요청 데이터에 없는 항목

                // 삭제 대상 항목 제거
                if (IDsToDelete.Any())
                {
                    _db.BannerPosition.RemoveRange(
                        await _db.BannerPosition.Where(c => IDsToDelete.Contains(c.ID) && !c.BannerItem.Any()).ToListAsync()
                    );
                }

                foreach (var row in request)
                {
                    // 중복 확인
                    if (await _db.BannerPosition.AnyAsync(c => c.Code == row.Code && c.ID != row.ID))
                    {
                        throw new Exception($"{row.Code} `Code`는 이미 존재합니다.");
                    }

                    if (row.ID == 0)
                    {
                        row.CreatedAt = DateTime.UtcNow;

                        await _db.BannerPosition.AddAsync(row);
                    }
                    else
                    {
                        var bannerPosition = await _db.BannerPosition.FirstOrDefaultAsync(c => c.ID == row.ID);
                        if (bannerPosition == null)
                        {
                            throw new Exception($"ID {row.ID}에 해당하는 정보가 없습니다.");
                        }

                        bannerPosition.Code = row.Code;
                        bannerPosition.Subject = row.Subject;
                        bannerPosition.IsActive = row.IsActive;
                        bannerPosition.UpdatedAt = DateTime.UtcNow;

                        _db.BannerPosition.Update(bannerPosition);
                    }
                }

                await transaction.CommitAsync();

                int affectedRows = await _db.SaveChangesAsync();
                if (affectedRows <= 0)
                {
                    throw new Exception("저장 중 오류가 발생했습니다.");
                }

                await _redisRepository.DeleteAsync(RedisConst.BannerKey);

                string message = "배너 위치가 저장되었습니다.";
                TempData["SuccessMessage"] = message;
                _logger.LogInformation(message);

                return RedirectToAction("Index");
            }
            catch (Exception e)
            {
                await transaction.RollbackAsync();

                TempData["ErrorMessages"] = e.Message;
                _logger.LogError(e, e.Message);

                return Index();
            }
        }
    }
}
