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

namespace LittleShop.Services;

public class CustomerService : ICustomerService
{
    private readonly LittleShopContext _context;
    private readonly IMapper _mapper;
    private readonly ILogger<CustomerService> _logger;

    public CustomerService(LittleShopContext context, IMapper mapper, ILogger<CustomerService> logger)
    {
        _context = context;
        _mapper = mapper;
        _logger = logger;
    }

    public async Task<CustomerDto?> GetCustomerByIdAsync(Guid id)
    {
        var customer = await _context.Customers
            .Include(c => c.Orders)
            .FirstOrDefaultAsync(c => c.Id == id);

        if (customer == null) return null;

        var dto = _mapper.Map<CustomerDto>(customer);
        dto.DisplayName = customer.DisplayName;
        dto.CustomerType = customer.CustomerType;
        return dto;
    }

    public async Task<CustomerDto?> GetCustomerByTelegramUserIdAsync(long telegramUserId)
    {
        var customer = await _context.Customers
            .Include(c => c.Orders)
            .FirstOrDefaultAsync(c => c.TelegramUserId == telegramUserId);

        if (customer == null) return null;

        var dto = _mapper.Map<CustomerDto>(customer);
        dto.DisplayName = customer.DisplayName;
        dto.CustomerType = customer.CustomerType;
        return dto;
    }

    public async Task<CustomerDto> CreateCustomerAsync(CreateCustomerDto createCustomerDto)
    {
        // Check if customer already exists
        var existingCustomer = await _context.Customers
            .FirstOrDefaultAsync(c => c.TelegramUserId == createCustomerDto.TelegramUserId);
        
        if (existingCustomer != null)
        {
            throw new InvalidOperationException($"Customer with Telegram ID {createCustomerDto.TelegramUserId} already exists");
        }

        var customer = _mapper.Map<Customer>(createCustomerDto);
        customer.Id = Guid.NewGuid();
        customer.CreatedAt = DateTime.UtcNow;
        customer.UpdatedAt = DateTime.UtcNow;
        customer.LastActiveAt = DateTime.UtcNow;
        customer.IsActive = true;

        // Set data retention date (default: 2 years after creation)
        customer.DataRetentionDate = DateTime.UtcNow.AddYears(2);

        _context.Customers.Add(customer);
        await _context.SaveChangesAsync();

        _logger.LogInformation("Created new customer {CustomerId} for Telegram user {TelegramUserId}", 
            customer.Id, customer.TelegramUserId);

        var dto = _mapper.Map<CustomerDto>(customer);
        dto.DisplayName = customer.DisplayName;
        dto.CustomerType = customer.CustomerType;
        return dto;
    }

    public async Task<CustomerDto?> UpdateCustomerAsync(Guid id, UpdateCustomerDto updateCustomerDto)
    {
        var customer = await _context.Customers.FindAsync(id);
        if (customer == null) return null;

        _mapper.Map(updateCustomerDto, customer);
        customer.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();

        _logger.LogInformation("Updated customer {CustomerId}", id);

        var dto = _mapper.Map<CustomerDto>(customer);
        dto.DisplayName = customer.DisplayName;
        dto.CustomerType = customer.CustomerType;
        return dto;
    }

    public async Task<bool> DeleteCustomerAsync(Guid id)
    {
        var customer = await _context.Customers.FindAsync(id);
        if (customer == null) return false;

        // Instead of hard delete, mark as inactive for data retention compliance
        customer.IsActive = false;
        customer.DataRetentionDate = DateTime.UtcNow.AddDays(30); // Delete in 30 days
        customer.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();

        _logger.LogInformation("Marked customer {CustomerId} for deletion", id);
        return true;
    }

    public async Task<IEnumerable<CustomerDto>> GetAllCustomersAsync()
    {
        var customers = await _context.Customers
            .Where(c => c.IsActive)
            .Include(c => c.Orders)
            .OrderByDescending(c => c.LastActiveAt)
            .ToListAsync();

        return customers.Select(c =>
        {
            var dto = _mapper.Map<CustomerDto>(c);
            dto.DisplayName = c.DisplayName;
            dto.CustomerType = c.CustomerType;
            return dto;
        });
    }

    public async Task<IEnumerable<CustomerDto>> SearchCustomersAsync(string searchTerm)
    {
        var query = _context.Customers
            .Where(c => c.IsActive)
            .Include(c => c.Orders)
            .AsQueryable();

        if (!string.IsNullOrWhiteSpace(searchTerm))
        {
            searchTerm = searchTerm.ToLower();
            query = query.Where(c =>
                c.TelegramUsername.ToLower().Contains(searchTerm) ||
                c.TelegramDisplayName.ToLower().Contains(searchTerm) ||
                c.TelegramFirstName.ToLower().Contains(searchTerm) ||
                c.TelegramLastName.ToLower().Contains(searchTerm) ||
                (c.Email != null && c.Email.ToLower().Contains(searchTerm)));
        }

        var customers = await query
            .OrderByDescending(c => c.LastActiveAt)
            .Take(50) // Limit search results
            .ToListAsync();

        return customers.Select(c =>
        {
            var dto = _mapper.Map<CustomerDto>(c);
            dto.DisplayName = c.DisplayName;
            dto.CustomerType = c.CustomerType;
            return dto;
        });
    }

    public async Task<CustomerDto?> GetOrCreateCustomerAsync(long telegramUserId, string displayName, string username = "", string firstName = "", string lastName = "")
    {
        // Try to find existing customer
        var customer = await _context.Customers
            .Include(c => c.Orders)
            .FirstOrDefaultAsync(c => c.TelegramUserId == telegramUserId);

        if (customer != null)
        {
            // Update customer information if provided
            bool updated = false;
            
            if (!string.IsNullOrEmpty(displayName) && customer.TelegramDisplayName != displayName)
            {
                customer.TelegramDisplayName = displayName;
                updated = true;
            }
            
            if (!string.IsNullOrEmpty(username) && customer.TelegramUsername != username)
            {
                customer.TelegramUsername = username;
                updated = true;
            }
            
            if (!string.IsNullOrEmpty(firstName) && customer.TelegramFirstName != firstName)
            {
                customer.TelegramFirstName = firstName;
                updated = true;
            }
            
            if (!string.IsNullOrEmpty(lastName) && customer.TelegramLastName != lastName)
            {
                customer.TelegramLastName = lastName;
                updated = true;
            }

            customer.LastActiveAt = DateTime.UtcNow;
            
            if (updated)
            {
                customer.UpdatedAt = DateTime.UtcNow;
                await _context.SaveChangesAsync();
                _logger.LogInformation("Updated existing customer {CustomerId} information", customer.Id);
            }
            else
            {
                await _context.SaveChangesAsync(); // Just update LastActiveAt
            }

            var existingDto = _mapper.Map<CustomerDto>(customer);
            existingDto.DisplayName = customer.DisplayName;
            existingDto.CustomerType = customer.CustomerType;
            return existingDto;
        }

        // Create new customer
        customer = new Customer
        {
            Id = Guid.NewGuid(),
            TelegramUserId = telegramUserId,
            TelegramUsername = username,
            TelegramDisplayName = displayName,
            TelegramFirstName = firstName,
            TelegramLastName = lastName,
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow,
            LastActiveAt = DateTime.UtcNow,
            DataRetentionDate = DateTime.UtcNow.AddYears(2),
            IsActive = true,
            AllowOrderUpdates = true,
            AllowMarketing = false,
            Language = "en",
            Timezone = "UTC"
        };

        _context.Customers.Add(customer);
        await _context.SaveChangesAsync();

        _logger.LogInformation("Created new customer {CustomerId} for Telegram user {TelegramUserId} ({DisplayName})", 
            customer.Id, telegramUserId, displayName);

        var dto = _mapper.Map<CustomerDto>(customer);
        dto.DisplayName = customer.DisplayName;
        dto.CustomerType = customer.CustomerType;
        return dto;
    }

    public async Task UpdateCustomerMetricsAsync(Guid customerId)
    {
        var customer = await _context.Customers
            .Include(c => c.Orders)
            .FirstOrDefaultAsync(c => c.Id == customerId);

        if (customer == null) return;

        customer.UpdateMetrics();
        await _context.SaveChangesAsync();

        _logger.LogInformation("Updated metrics for customer {CustomerId}", customerId);
    }

    public async Task<bool> BlockCustomerAsync(Guid customerId, string reason)
    {
        var customer = await _context.Customers.FindAsync(customerId);
        if (customer == null) return false;

        customer.IsBlocked = true;
        customer.BlockReason = reason;
        customer.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();

        _logger.LogWarning("Blocked customer {CustomerId} - Reason: {Reason}", customerId, reason);
        return true;
    }

    public async Task<bool> UnblockCustomerAsync(Guid customerId)
    {
        var customer = await _context.Customers.FindAsync(customerId);
        if (customer == null) return false;

        customer.IsBlocked = false;
        customer.BlockReason = null;
        customer.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();

        _logger.LogInformation("Unblocked customer {CustomerId}", customerId);
        return true;
    }
}