using Microsoft.EntityFrameworkCore;
using LittleShop.Data;
using LittleShop.Models;
using LittleShop.DTOs;

namespace LittleShop.Services;

public class ProductService : IProductService
{
    private readonly LittleShopContext _context;
    private readonly IWebHostEnvironment _environment;

    public ProductService(LittleShopContext context, IWebHostEnvironment environment)
    {
        _context = context;
        _environment = environment;
    }

    public async Task<IEnumerable<ProductDto>> GetAllProductsAsync()
    {
        return await _context.Products
            .Include(p => p.Category)
            .Include(p => p.Photos)
            .Where(p => p.IsActive)
            .Select(p => new ProductDto
            {
                Id = p.Id,
                Name = p.Name,
                Description = p.Description,
                Price = p.Price,
                Weight = p.Weight,
                WeightUnit = p.WeightUnit,
                StockQuantity = p.StockQuantity,
                CategoryId = p.CategoryId,
                CategoryName = p.Category.Name,
                CreatedAt = p.CreatedAt,
                UpdatedAt = p.UpdatedAt,
                IsActive = p.IsActive,
                Photos = p.Photos.OrderBy(ph => ph.SortOrder).Select(ph => new ProductPhotoDto
                {
                    Id = ph.Id,
                    FileName = ph.FileName,
                    FilePath = ph.FilePath,
                    AltText = ph.AltText,
                    SortOrder = ph.SortOrder
                }).ToList()
            })
            .ToListAsync();
    }

    public async Task<IEnumerable<ProductDto>> GetProductsByCategoryAsync(Guid categoryId)
    {
        return await _context.Products
            .Include(p => p.Category)
            .Include(p => p.Photos)
            .Where(p => p.IsActive && p.CategoryId == categoryId)
            .Select(p => new ProductDto
            {
                Id = p.Id,
                Name = p.Name,
                Description = p.Description,
                Price = p.Price,
                Weight = p.Weight,
                WeightUnit = p.WeightUnit,
                StockQuantity = p.StockQuantity,
                CategoryId = p.CategoryId,
                CategoryName = p.Category.Name,
                CreatedAt = p.CreatedAt,
                UpdatedAt = p.UpdatedAt,
                IsActive = p.IsActive,
                Photos = p.Photos.OrderBy(ph => ph.SortOrder).Select(ph => new ProductPhotoDto
                {
                    Id = ph.Id,
                    FileName = ph.FileName,
                    FilePath = ph.FilePath,
                    AltText = ph.AltText,
                    SortOrder = ph.SortOrder
                }).ToList()
            })
            .ToListAsync();
    }

    public async Task<ProductDto?> GetProductByIdAsync(Guid id)
    {
        var product = await _context.Products
            .Include(p => p.Category)
            .Include(p => p.Photos)
            .FirstOrDefaultAsync(p => p.Id == id);

        if (product == null) return null;

        return new ProductDto
        {
            Id = product.Id,
            Name = product.Name,
            Description = product.Description,
            Price = product.Price,
            Weight = product.Weight,
            WeightUnit = product.WeightUnit,
            StockQuantity = product.StockQuantity,
            CategoryId = product.CategoryId,
            CategoryName = product.Category.Name,
            CreatedAt = product.CreatedAt,
            UpdatedAt = product.UpdatedAt,
            IsActive = product.IsActive,
            Photos = product.Photos.OrderBy(ph => ph.SortOrder).Select(ph => new ProductPhotoDto
            {
                Id = ph.Id,
                FileName = ph.FileName,
                FilePath = ph.FilePath,
                AltText = ph.AltText,
                SortOrder = ph.SortOrder
            }).ToList()
        };
    }

    public async Task<ProductDto> CreateProductAsync(CreateProductDto createProductDto)
    {
        var product = new Product
        {
            Id = Guid.NewGuid(),
            Name = createProductDto.Name,
            Description = string.IsNullOrEmpty(createProductDto.Description) ? " " : createProductDto.Description,
            Price = createProductDto.Price,
            Weight = createProductDto.Weight,
            WeightUnit = createProductDto.WeightUnit,
            StockQuantity = createProductDto.StockQuantity,
            CategoryId = createProductDto.CategoryId,
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow,
            IsActive = true
        };

        _context.Products.Add(product);
        await _context.SaveChangesAsync();

        var category = await _context.Categories.FindAsync(createProductDto.CategoryId);

        return new ProductDto
        {
            Id = product.Id,
            Name = product.Name,
            Description = product.Description,
            Price = product.Price,
            Weight = product.Weight,
            WeightUnit = product.WeightUnit,
            CategoryId = product.CategoryId,
            CategoryName = category?.Name ?? "",
            CreatedAt = product.CreatedAt,
            UpdatedAt = product.UpdatedAt,
            IsActive = product.IsActive,
            Photos = new List<ProductPhotoDto>()
        };
    }

    public async Task<bool> UpdateProductAsync(Guid id, UpdateProductDto updateProductDto)
    {
        var product = await _context.Products.FindAsync(id);
        if (product == null) return false;

        if (!string.IsNullOrEmpty(updateProductDto.Name))
            product.Name = updateProductDto.Name;

        if (!string.IsNullOrEmpty(updateProductDto.Description))
            product.Description = updateProductDto.Description;

        if (updateProductDto.Price.HasValue)
            product.Price = updateProductDto.Price.Value;

        if (updateProductDto.Weight.HasValue)
            product.Weight = updateProductDto.Weight.Value;

        if (updateProductDto.WeightUnit.HasValue)
            product.WeightUnit = updateProductDto.WeightUnit.Value;

        if (updateProductDto.StockQuantity.HasValue)
            product.StockQuantity = updateProductDto.StockQuantity.Value;

        if (updateProductDto.CategoryId.HasValue)
            product.CategoryId = updateProductDto.CategoryId.Value;

        if (updateProductDto.IsActive.HasValue)
            product.IsActive = updateProductDto.IsActive.Value;

        product.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();
        return true;
    }

    public async Task<bool> DeleteProductAsync(Guid id)
    {
        var product = await _context.Products.FindAsync(id);
        if (product == null) return false;

        product.IsActive = false;
        await _context.SaveChangesAsync();
        return true;
    }

    public async Task<bool> AddProductPhotoAsync(Guid productId, IFormFile file, string? altText = null)
    {
        var product = await _context.Products.FindAsync(productId);
        if (product == null) return false;

        var uploadsPath = Path.Combine(_environment.WebRootPath ?? "wwwroot", "uploads", "products");
        Directory.CreateDirectory(uploadsPath);

        var fileName = $"{Guid.NewGuid()}_{file.FileName}";
        var filePath = Path.Combine(uploadsPath, fileName);

        using (var stream = new FileStream(filePath, FileMode.Create))
        {
            await file.CopyToAsync(stream);
        }

        var maxSortOrder = await _context.ProductPhotos
            .Where(pp => pp.ProductId == productId)
            .Select(pp => (int?)pp.SortOrder)
            .MaxAsync() ?? 0;

        var productPhoto = new ProductPhoto
        {
            Id = Guid.NewGuid(),
            ProductId = productId,
            FileName = fileName,
            FilePath = $"/uploads/products/{fileName}",
            AltText = altText,
            SortOrder = maxSortOrder + 1,
            CreatedAt = DateTime.UtcNow
        };

        _context.ProductPhotos.Add(productPhoto);
        await _context.SaveChangesAsync();
        return true;
    }

    public async Task<bool> RemoveProductPhotoAsync(Guid productId, Guid photoId)
    {
        var photo = await _context.ProductPhotos
            .FirstOrDefaultAsync(pp => pp.Id == photoId && pp.ProductId == productId);

        if (photo == null) return false;

        var physicalPath = Path.Combine(_environment.WebRootPath, photo.FilePath.TrimStart('/'));
        if (File.Exists(physicalPath))
        {
            File.Delete(physicalPath);
        }

        _context.ProductPhotos.Remove(photo);
        await _context.SaveChangesAsync();
        return true;
    }

    public async Task<ProductPhotoDto?> AddProductPhotoAsync(CreateProductPhotoDto photoDto)
    {
        var product = await _context.Products.FindAsync(photoDto.ProductId);
        if (product == null) return null;

        var existingPhotos = await _context.ProductPhotos
            .Where(pp => pp.ProductId == photoDto.ProductId)
            .ToListAsync();
        
        var maxSortOrder = existingPhotos.Any() ? existingPhotos.Max(pp => pp.SortOrder) : 0;

        var productPhoto = new ProductPhoto
        {
            Id = Guid.NewGuid(),
            ProductId = photoDto.ProductId,
            FileName = Path.GetFileName(photoDto.PhotoUrl),
            FilePath = photoDto.PhotoUrl,
            AltText = photoDto.AltText,
            SortOrder = photoDto.DisplayOrder > 0 ? photoDto.DisplayOrder : maxSortOrder + 1,
            CreatedAt = DateTime.UtcNow
        };

        _context.ProductPhotos.Add(productPhoto);
        await _context.SaveChangesAsync();

        return new ProductPhotoDto
        {
            Id = productPhoto.Id,
            FileName = productPhoto.FileName,
            FilePath = productPhoto.FilePath,
            AltText = productPhoto.AltText,
            SortOrder = productPhoto.SortOrder
        };
    }

    public async Task<IEnumerable<ProductDto>> SearchProductsAsync(string searchTerm)
    {
        var query = _context.Products
            .Include(p => p.Category)
            .Include(p => p.Photos)
            .Where(p => p.IsActive);

        if (!string.IsNullOrWhiteSpace(searchTerm))
        {
            searchTerm = searchTerm.ToLower();
            query = query.Where(p => 
                p.Name.ToLower().Contains(searchTerm) || 
                p.Description.ToLower().Contains(searchTerm));
        }

        return await query.Select(p => new ProductDto
        {
            Id = p.Id,
            Name = p.Name,
            Description = p.Description,
            Price = p.Price,
            Weight = p.Weight,
            WeightUnit = p.WeightUnit,
            StockQuantity = p.StockQuantity,
            CategoryId = p.CategoryId,
            CategoryName = p.Category.Name,
            CreatedAt = p.CreatedAt,
            UpdatedAt = p.UpdatedAt,
            IsActive = p.IsActive,
            Photos = p.Photos.OrderBy(ph => ph.SortOrder).Select(ph => new ProductPhotoDto
            {
                Id = ph.Id,
                FileName = ph.FileName,
                FilePath = ph.FilePath,
                AltText = ph.AltText,
                SortOrder = ph.SortOrder
            }).ToList()
        }).ToListAsync();
    }
}