using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; using SkyArtShop.Models; using SkyArtShop.Services; namespace SkyArtShop.Controllers; [Route("admin/products")] [Authorize(Roles = "Admin,MasterAdmin")] public class AdminProductsController : Controller { private readonly PostgreSQLService _pgService; private readonly SlugService _slugService; private readonly string _productsCollection = "Products"; public AdminProductsController(PostgreSQLService pgService, SlugService slugService) { _pgService = pgService; _slugService = slugService; } [HttpGet("")] public async Task Index() { return View((await _pgService.GetAllAsync(_productsCollection)).OrderByDescending((Product p) => p.CreatedAt).ToList()); } [HttpGet("create")] public IActionResult Create() { return View(new Product()); } [HttpPost("create")] public async Task Create(Product product, string? ProductVariantsJson) { try { base.ModelState.Remove("ShortDescription"); base.ModelState.Remove("Description"); base.ModelState.Remove("ProductVariantsJson"); base.ModelState.Remove("Id"); base.ModelState.Remove("Slug"); base.ModelState.Remove("ImageUrl"); base.ModelState.Remove("Images"); if (!base.ModelState.IsValid) { foreach (ModelError item in base.ModelState.Values.SelectMany((ModelStateEntry v) => v.Errors)) { Console.WriteLine("[CREATE] Validation Error: " + item.ErrorMessage); } return View(product); } } catch (Exception ex) { Console.WriteLine("[CREATE] Error: " + ex.Message); Console.WriteLine("[CREATE] Stack: " + ex.StackTrace); base.TempData["ErrorMessage"] = "Error creating product: " + ex.Message; return View(product); } if (!base.Request.Form.ContainsKey("IsActive")) { product.IsActive = false; } if (!base.Request.Form.ContainsKey("IsFeatured")) { product.IsFeatured = false; } if (!base.Request.Form.ContainsKey("IsTopSeller")) { product.IsTopSeller = false; } Console.WriteLine("[CREATE] ProductVariantsJson received: '" + (ProductVariantsJson ?? "NULL") + "'"); if (!string.IsNullOrEmpty(ProductVariantsJson)) { try { product.Variants = JsonSerializer.Deserialize>(ProductVariantsJson) ?? new List(); Console.WriteLine($"[CREATE] Variants deserialized successfully: {product.Variants.Count} variants"); foreach (ProductVariant variant in product.Variants) { Console.WriteLine($" - {variant.ColorName} ({variant.ColorHex}) with {variant.Images?.Count ?? 0} images, Stock: {variant.StockQuantity}"); } } catch (Exception ex2) { Console.WriteLine("[CREATE] Error parsing variants: " + ex2.Message); Console.WriteLine("[CREATE] JSON was: " + ProductVariantsJson); product.Variants = new List(); } } else { Console.WriteLine("[CREATE] No variants provided - ProductVariantsJson is null or empty"); product.Variants = new List(); } product.Colors = new List(); product.Color = string.Empty; try { product.CreatedAt = DateTime.UtcNow; product.UpdatedAt = DateTime.UtcNow; product.Slug = _slugService.GenerateSlug(product.Name); await _pgService.InsertAsync(_productsCollection, product); base.TempData["SuccessMessage"] = "Product created successfully!"; return RedirectToAction("Index"); } catch (Exception ex3) { Console.WriteLine("[CREATE] Database Error: " + ex3.Message); Console.WriteLine("[CREATE] Stack: " + ex3.StackTrace); base.TempData["ErrorMessage"] = "Error saving product: " + ex3.Message; return View(product); } } [HttpGet("edit/{id}")] public async Task Edit(string id) { Product product = await _pgService.GetByIdAsync(_productsCollection, id); if (product == null) { return NotFound(); } return View("Create", product); } [HttpPost("edit/{id}")] public async Task Edit(string id, Product product, string? ProductVariantsJson) { try { base.ModelState.Remove("Images"); base.ModelState.Remove("Slug"); base.ModelState.Remove("ShortDescription"); base.ModelState.Remove("Description"); base.ModelState.Remove("ProductVariantsJson"); base.ModelState.Remove("Id"); base.ModelState.Remove("ImageUrl"); if (!base.ModelState.IsValid) { foreach (ModelError item in base.ModelState.Values.SelectMany((ModelStateEntry v) => v.Errors)) { Console.WriteLine("[EDIT] Validation Error: " + item.ErrorMessage); } return View("Create", product); } } catch (Exception ex) { Console.WriteLine("[EDIT] Error: " + ex.Message); Console.WriteLine("[EDIT] Stack: " + ex.StackTrace); base.TempData["ErrorMessage"] = "Error updating product: " + ex.Message; return View("Create", product); } if (!base.Request.Form.ContainsKey("IsActive")) { product.IsActive = false; } if (!base.Request.Form.ContainsKey("IsFeatured")) { product.IsFeatured = false; } if (!base.Request.Form.ContainsKey("IsTopSeller")) { product.IsTopSeller = false; } Product existingProduct = await _pgService.GetByIdAsync(_productsCollection, id); if (existingProduct == null) { base.TempData["ErrorMessage"] = "Product not found."; return RedirectToAction("Index"); } existingProduct.Name = product.Name; existingProduct.ShortDescription = product.ShortDescription; existingProduct.Description = product.Description; existingProduct.Price = product.Price; existingProduct.Category = product.Category; existingProduct.Color = product.Color; Console.WriteLine("[EDIT] ProductVariantsJson received: '" + (ProductVariantsJson ?? "NULL") + "'"); if (!string.IsNullOrEmpty(ProductVariantsJson)) { try { existingProduct.Variants = JsonSerializer.Deserialize>(ProductVariantsJson) ?? new List(); Console.WriteLine($"[EDIT] Variants deserialized successfully: {existingProduct.Variants.Count} variants"); foreach (ProductVariant variant in existingProduct.Variants) { Console.WriteLine($" - {variant.ColorName} ({variant.ColorHex}) with {variant.Images?.Count ?? 0} images, Stock: {variant.StockQuantity}"); } } catch (Exception ex2) { Console.WriteLine("[EDIT] Error parsing variants: " + ex2.Message); Console.WriteLine("[EDIT] JSON was: " + ProductVariantsJson); existingProduct.Variants = new List(); } } else { Console.WriteLine("[EDIT] No variants provided - ProductVariantsJson is null or empty"); existingProduct.Variants = new List(); } existingProduct.Colors = new List(); existingProduct.Color = string.Empty; existingProduct.StockQuantity = product.StockQuantity; existingProduct.IsFeatured = product.IsFeatured; existingProduct.IsTopSeller = product.IsTopSeller; existingProduct.IsActive = product.IsActive; existingProduct.UpdatedAt = DateTime.UtcNow; existingProduct.Slug = _slugService.GenerateSlug(product.Name); if (base.Request.Form.ContainsKey("Images")) { List list = (existingProduct.Images = (from img in base.Request.Form["Images"] where !string.IsNullOrEmpty(img) select (img)).ToList()); if (list.Any() && string.IsNullOrEmpty(product.ImageUrl)) { existingProduct.ImageUrl = list[0] ?? ""; } } if (!string.IsNullOrEmpty(product.ImageUrl)) { existingProduct.ImageUrl = product.ImageUrl; } if (!string.IsNullOrEmpty(product.SKU)) { existingProduct.SKU = product.SKU; } if (product.CostPrice > 0m) { existingProduct.CostPrice = product.CostPrice; } try { await _pgService.UpdateAsync(_productsCollection, id, existingProduct); base.TempData["SuccessMessage"] = "Product updated successfully!"; return RedirectToAction("Index"); } catch (Exception ex3) { Console.WriteLine("[EDIT] Database Error: " + ex3.Message); Console.WriteLine("[EDIT] Stack: " + ex3.StackTrace); base.TempData["ErrorMessage"] = "Error saving product changes: " + ex3.Message; return View("Create", existingProduct); } } [HttpPost("delete/{id}")] public async Task Delete(string id) { await _pgService.DeleteAsync(_productsCollection, id); base.TempData["SuccessMessage"] = "Product deleted successfully!"; return RedirectToAction("Index"); } }