using Microsoft.EntityFrameworkCore;
using System.Globalization;
using System.Text;
using LittleShop.Data;
using LittleShop.Models;
using LittleShop.DTOs;
using LittleShop.Enums;

namespace LittleShop.Services;

public interface IProductImportService
{
    Task<ProductImportResultDto> ImportFromCsvAsync(Stream csvStream);
    Task<ProductImportResultDto> ImportFromTextAsync(string csvText);
    string GenerateTemplateAsCsv();
    Task<string> ExportProductsAsCsvAsync();
}

public class ProductImportService : IProductImportService
{
    private readonly LittleShopContext _context;
    private readonly IProductService _productService;
    private readonly ICategoryService _categoryService;
    private readonly ILogger<ProductImportService> _logger;

    public ProductImportService(
        LittleShopContext context,
        IProductService productService,
        ICategoryService categoryService,
        ILogger<ProductImportService> logger)
    {
        _context = context;
        _productService = productService;
        _categoryService = categoryService;
        _logger = logger;
    }

    public async Task<ProductImportResultDto> ImportFromCsvAsync(Stream csvStream)
    {
        using var reader = new StreamReader(csvStream);
        var csvText = await reader.ReadToEndAsync();
        return await ImportFromTextAsync(csvText);
    }

    public async Task<ProductImportResultDto> ImportFromTextAsync(string csvText)
    {
        var result = new ProductImportResultDto();
        var lines = csvText.Split('\n', StringSplitOptions.RemoveEmptyEntries);

        if (lines.Length == 0)
        {
            result.Errors.Add(new ProductImportErrorDto
            {
                RowNumber = 0,
                ProductName = "File",
                ErrorMessages = { "CSV file is empty" }
            });
            return result;
        }

        // Parse header
        var headers = ParseCsvLine(lines[0]);
        var expectedHeaders = new[] { "Name", "Description", "Price", "Weight", "WeightUnit", "StockQuantity", "CategoryName", "IsActive", "Variations", "PhotoUrls" };

        // Validate headers
        foreach (var expectedHeader in expectedHeaders.Take(7)) // First 7 are required
        {
            if (!headers.Contains(expectedHeader, StringComparer.OrdinalIgnoreCase))
            {
                result.Errors.Add(new ProductImportErrorDto
                {
                    RowNumber = 0,
                    ProductName = "Header",
                    ErrorMessages = { $"Missing required column: {expectedHeader}" }
                });
            }
        }

        if (result.Errors.Any())
            return result;

        result.TotalRows = lines.Length - 1; // Exclude header

        // Get categories for lookup
        var categories = await _categoryService.GetAllCategoriesAsync();
        var categoryLookup = categories.ToDictionary(c => c.Name, c => c.Id, StringComparer.OrdinalIgnoreCase);

        // Process data rows
        for (int i = 1; i < lines.Length; i++)
        {
            try
            {
                var values = ParseCsvLine(lines[i]);
                if (values.Length < 7) // Minimum required columns
                {
                    result.Errors.Add(new ProductImportErrorDto
                    {
                        RowNumber = i + 1,
                        ProductName = values.Length > 0 ? values[0] : "Unknown",
                        ErrorMessages = { "Insufficient columns in row" }
                    });
                    result.FailedImports++;
                    continue;
                }

                var importDto = new ProductImportDto
                {
                    Name = GetValue(values, headers, "Name", ""),
                    Description = GetValue(values, headers, "Description", ""),
                    Price = decimal.Parse(GetValue(values, headers, "Price", "0"), CultureInfo.InvariantCulture),
                    Weight = decimal.Parse(GetValue(values, headers, "Weight", "0"), CultureInfo.InvariantCulture),
                    WeightUnit = GetValue(values, headers, "WeightUnit", "Grams"),
                    StockQuantity = int.Parse(GetValue(values, headers, "StockQuantity", "0")),
                    CategoryName = GetValue(values, headers, "CategoryName", ""),
                    IsActive = bool.Parse(GetValue(values, headers, "IsActive", "true")),
                    Variations = GetValue(values, headers, "Variations", null),
                    PhotoUrls = GetValue(values, headers, "PhotoUrls", null)
                };

                await ImportSingleProductAsync(importDto, categoryLookup, result, i + 1);
            }
            catch (Exception ex)
            {
                result.Errors.Add(new ProductImportErrorDto
                {
                    RowNumber = i + 1,
                    ProductName = "Parse Error",
                    ErrorMessages = { ex.Message }
                });
                result.FailedImports++;
            }
        }

        _logger.LogInformation("Product import completed: {Success} successful, {Failed} failed", result.SuccessfulImports, result.FailedImports);
        return result;
    }

    private async Task ImportSingleProductAsync(ProductImportDto importDto, Dictionary<string, Guid> categoryLookup, ProductImportResultDto result, int rowNumber)
    {
        var errors = new List<string>();

        // Validate category
        if (!categoryLookup.TryGetValue(importDto.CategoryName, out var categoryId))
        {
            errors.Add($"Category '{importDto.CategoryName}' not found");
        }

        // Validate weight unit
        if (!Enum.TryParse<ProductWeightUnit>(importDto.WeightUnit, true, out var weightUnit))
        {
            errors.Add($"Invalid weight unit: {importDto.WeightUnit}");
        }

        if (errors.Any())
        {
            result.Errors.Add(new ProductImportErrorDto
            {
                RowNumber = rowNumber,
                ProductName = importDto.Name,
                ErrorMessages = errors
            });
            result.FailedImports++;
            return;
        }

        try
        {
            // Create product
            var createProductDto = new CreateProductDto
            {
                Name = importDto.Name,
                Description = importDto.Description,
                Price = importDto.Price,
                Weight = importDto.Weight,
                WeightUnit = weightUnit,
                StockQuantity = importDto.StockQuantity,
                CategoryId = categoryId
            };

            var product = await _productService.CreateProductAsync(createProductDto);
            result.ImportedProducts.Add(product);

            // Import variations if provided
            if (!string.IsNullOrEmpty(importDto.Variations))
            {
                await ImportProductVariationsAsync(product.Id, importDto.Variations);
            }

            // Import photos if provided
            if (!string.IsNullOrEmpty(importDto.PhotoUrls))
            {
                await ImportProductPhotosAsync(product.Id, importDto.PhotoUrls);
            }

            result.SuccessfulImports++;
        }
        catch (Exception ex)
        {
            result.Errors.Add(new ProductImportErrorDto
            {
                RowNumber = rowNumber,
                ProductName = importDto.Name,
                ErrorMessages = { ex.Message }
            });
            result.FailedImports++;
        }
    }

    private async Task ImportProductVariationsAsync(Guid productId, string variationsText)
    {
        // Format: "Single Item:1:10.00;Twin Pack:2:19.00;Triple Pack:3:25.00"
        var variations = variationsText.Split(';', StringSplitOptions.RemoveEmptyEntries);

        for (int i = 0; i < variations.Length; i++)
        {
            var parts = variations[i].Split(':', StringSplitOptions.RemoveEmptyEntries);
            if (parts.Length >= 3)
            {
                var variationDto = new CreateProductVariationDto
                {
                    ProductId = productId,
                    Name = parts[0].Trim(),
                    Description = parts.Length > 3 ? parts[3].Trim() : "",
                    Quantity = int.Parse(parts[1].Trim()),
                    Price = decimal.Parse(parts[2].Trim(), CultureInfo.InvariantCulture),
                    SortOrder = i
                };

                await _productService.CreateProductVariationAsync(variationDto);
            }
        }
    }

    private async Task ImportProductPhotosAsync(Guid productId, string photoUrlsText)
    {
        // Format: "url1;url2;url3"
        var urls = photoUrlsText.Split(';', StringSplitOptions.RemoveEmptyEntries);

        for (int i = 0; i < urls.Length; i++)
        {
            var photoDto = new CreateProductPhotoDto
            {
                ProductId = productId,
                PhotoUrl = urls[i].Trim(),
                DisplayOrder = i + 1
            };

            await _productService.AddProductPhotoAsync(photoDto);
        }
    }

    public string GenerateTemplateAsCsv()
    {
        var sb = new StringBuilder();

        // Header
        sb.AppendLine("Name,Description,Price,Weight,WeightUnit,StockQuantity,CategoryName,IsActive,Variations,PhotoUrls");

        // Example rows
        sb.AppendLine("\"Example Product 1\",\"High-quality example product with great features\",29.99,150,Grams,50,Electronics,true,\"Single Item:1:29.99;Twin Pack:2:55.00;Triple Pack:3:79.99\",\"https://example.com/photo1.jpg;https://example.com/photo2.jpg\"");
        sb.AppendLine("\"Example Product 2\",\"Another sample product for import testing\",19.99,200,Grams,25,Clothing,true,\"Individual:1:19.99;Pair:2:35.00\",\"\"");
        sb.AppendLine("\"Simple Product\",\"Basic product without variations\",9.99,100,Grams,100,Books,true,\"\",\"\"");

        return sb.ToString();
    }

    public async Task<string> ExportProductsAsCsvAsync()
    {
        var products = await _productService.GetAllProductsAsync();
        var sb = new StringBuilder();

        // Header
        sb.AppendLine("Name,Description,Price,Weight,WeightUnit,StockQuantity,CategoryName,IsActive,Variations,PhotoUrls");

        foreach (var product in products)
        {
            // Build variations string
            var variationsText = string.Join(";", product.Variations.OrderBy(v => v.SortOrder)
                .Select(v => $"{v.Name}:{v.Quantity}:{v.Price:F2}"));

            // Build photo URLs string
            var photoUrlsText = string.Join(";", product.Photos.OrderBy(p => p.SortOrder)
                .Select(p => p.FilePath));

            sb.AppendLine($"\"{product.Name}\",\"{product.Description}\",{product.Price:F2},{product.Weight:F2},{product.WeightUnit},{product.StockQuantity},\"{product.CategoryName}\",{product.IsActive.ToString().ToLower()},\"{variationsText}\",\"{photoUrlsText}\"");
        }

        return sb.ToString();
    }

    private string[] ParseCsvLine(string line)
    {
        var values = new List<string>();
        var inQuotes = false;
        var currentValue = new StringBuilder();

        for (int i = 0; i < line.Length; i++)
        {
            var c = line[i];

            if (c == '"')
            {
                inQuotes = !inQuotes;
            }
            else if (c == ',' && !inQuotes)
            {
                values.Add(currentValue.ToString().Trim());
                currentValue.Clear();
            }
            else
            {
                currentValue.Append(c);
            }
        }

        values.Add(currentValue.ToString().Trim());
        return values.ToArray();
    }

    private string GetValue(string[] values, string[] headers, string columnName, string defaultValue)
    {
        var index = Array.FindIndex(headers, h => h.Equals(columnName, StringComparison.OrdinalIgnoreCase));
        if (index >= 0 && index < values.Length)
        {
            var value = values[index].Trim('"', ' ');
            return string.IsNullOrEmpty(value) ? defaultValue : value;
        }
        return defaultValue;
    }
}