using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using DramaLing.Api.Data;
using DramaLing.Api.Models.Entities;
using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;

namespace DramaLing.Api.Controllers;

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class FlashcardsController : ControllerBase
{
    private readonly DramaLingDbContext _context;

    public FlashcardsController(DramaLingDbContext context)
    {
        _context = context;
    }

    private Guid GetUserId()
    {
        var userIdString = User.FindFirst(ClaimTypes.NameIdentifier)?.Value ??
                          User.FindFirst("sub")?.Value;

        if (Guid.TryParse(userIdString, out var userId))
            return userId;

        throw new UnauthorizedAccessException("Invalid user ID");
    }

    private async Task<Guid> GetOrCreateDefaultCardSetAsync(Guid userId)
    {
        // 嘗試找到預設卡組
        var defaultCardSet = await _context.CardSets
            .FirstOrDefaultAsync(cs => cs.UserId == userId && cs.IsDefault);

        if (defaultCardSet != null)
            return defaultCardSet.Id;

        // 如果沒有預設卡組，創建一個
        var newDefaultCardSet = new CardSet
        {
            Id = Guid.NewGuid(),
            UserId = userId,
            Name = "未分類",
            Description = "系統預設卡組，用於存放尚未分類的詞卡",
            Color = "bg-slate-700",
            IsDefault = true
        };

        _context.CardSets.Add(newDefaultCardSet);
        await _context.SaveChangesAsync();
        return newDefaultCardSet.Id;
    }

    [HttpGet]
    public async Task<ActionResult> GetFlashcards(
        [FromQuery] Guid? setId,
        [FromQuery] string? search,
        [FromQuery] bool favoritesOnly = false,
        [FromQuery] int limit = 50,
        [FromQuery] int offset = 0)
    {
        try
        {
            var userId = GetUserId();

            var query = _context.Flashcards
                .Include(f => f.CardSet)
                .Where(f => f.UserId == userId);

            if (setId.HasValue)
                query = query.Where(f => f.CardSetId == setId);

            if (!string.IsNullOrEmpty(search))
                query = query.Where(f => f.Word.Contains(search) || f.Translation.Contains(search));

            if (favoritesOnly)
                query = query.Where(f => f.IsFavorite);

            var total = await query.CountAsync();
            var flashcards = await query
                .OrderByDescending(f => f.CreatedAt)
                .Skip(offset)
                .Take(Math.Min(limit, 100))
                .Select(f => new
                {
                    f.Id,
                    f.Word,
                    f.Translation,
                    f.Definition,
                    f.PartOfSpeech,
                    f.Pronunciation,
                    f.Example,
                    f.ExampleTranslation,
                    f.MasteryLevel,
                    f.TimesReviewed,
                    f.IsFavorite,
                    f.NextReviewDate,
                    f.CreatedAt,
                    CardSet = new
                    {
                        f.CardSet.Name,
                        f.CardSet.Color
                    }
                })
                .ToListAsync();

            return Ok(new
            {
                Success = true,
                Data = new
                {
                    Flashcards = flashcards,
                    Total = total,
                    HasMore = offset + limit < total
                }
            });
        }
        catch (UnauthorizedAccessException)
        {
            return Unauthorized(new { Success = false, Error = "Unauthorized" });
        }
        catch (Exception ex)
        {
            return StatusCode(500, new
            {
                Success = false,
                Error = "Failed to fetch flashcards",
                Timestamp = DateTime.UtcNow
            });
        }
    }

    [HttpPost]
    public async Task<ActionResult> CreateFlashcard([FromBody] CreateFlashcardRequest request)
    {
        try
        {
            var userId = GetUserId();

            // 確定要使用的卡組ID
            Guid cardSetId;
            if (request.CardSetId.HasValue)
            {
                // 如果指定了卡組，驗證是否屬於用戶
                var cardSet = await _context.CardSets
                    .FirstOrDefaultAsync(cs => cs.Id == request.CardSetId.Value && cs.UserId == userId);

                if (cardSet == null)
                    return NotFound(new { Success = false, Error = "Card set not found" });

                cardSetId = request.CardSetId.Value;
            }
            else
            {
                // 如果沒有指定卡組，使用或創建預設卡組
                cardSetId = await GetOrCreateDefaultCardSetAsync(userId);
            }

            var flashcard = new Flashcard
            {
                Id = Guid.NewGuid(),
                UserId = userId,
                CardSetId = cardSetId,
                Word = request.Word.Trim(),
                Translation = request.Translation.Trim(),
                Definition = request.Definition.Trim(),
                PartOfSpeech = request.PartOfSpeech?.Trim(),
                Pronunciation = request.Pronunciation?.Trim(),
                Example = request.Example?.Trim(),
                ExampleTranslation = request.ExampleTranslation?.Trim()
            };

            _context.Flashcards.Add(flashcard);
            await _context.SaveChangesAsync();

            return Ok(new
            {
                Success = true,
                Data = flashcard,
                Message = "Flashcard created successfully"
            });
        }
        catch (UnauthorizedAccessException)
        {
            return Unauthorized(new { Success = false, Error = "Unauthorized" });
        }
        catch (Exception ex)
        {
            return StatusCode(500, new
            {
                Success = false,
                Error = "Failed to create flashcard",
                Timestamp = DateTime.UtcNow
            });
        }
    }

    [HttpGet("{id}")]
    public async Task<ActionResult> GetFlashcard(Guid id)
    {
        try
        {
            var userId = GetUserId();

            var flashcard = await _context.Flashcards
                .Include(f => f.CardSet)
                .FirstOrDefaultAsync(f => f.Id == id && f.UserId == userId);

            if (flashcard == null)
                return NotFound(new { Success = false, Error = "Flashcard not found" });

            return Ok(new { Success = true, Data = flashcard });
        }
        catch (UnauthorizedAccessException)
        {
            return Unauthorized(new { Success = false, Error = "Unauthorized" });
        }
        catch (Exception ex)
        {
            return StatusCode(500, new
            {
                Success = false,
                Error = "Failed to fetch flashcard",
                Timestamp = DateTime.UtcNow
            });
        }
    }

    [HttpPut("{id}")]
    public async Task<ActionResult> UpdateFlashcard(Guid id, [FromBody] UpdateFlashcardRequest request)
    {
        try
        {
            var userId = GetUserId();

            var flashcard = await _context.Flashcards
                .FirstOrDefaultAsync(f => f.Id == id && f.UserId == userId);

            if (flashcard == null)
                return NotFound(new { Success = false, Error = "Flashcard not found" });

            // 更新欄位
            if (!string.IsNullOrEmpty(request.Word))
                flashcard.Word = request.Word.Trim();
            if (!string.IsNullOrEmpty(request.Translation))
                flashcard.Translation = request.Translation.Trim();
            if (!string.IsNullOrEmpty(request.Definition))
                flashcard.Definition = request.Definition.Trim();
            if (request.PartOfSpeech != null)
                flashcard.PartOfSpeech = request.PartOfSpeech?.Trim();
            if (request.Pronunciation != null)
                flashcard.Pronunciation = request.Pronunciation?.Trim();
            if (request.Example != null)
                flashcard.Example = request.Example?.Trim();
            if (request.ExampleTranslation != null)
                flashcard.ExampleTranslation = request.ExampleTranslation?.Trim();
            if (request.IsFavorite.HasValue)
                flashcard.IsFavorite = request.IsFavorite.Value;

            flashcard.UpdatedAt = DateTime.UtcNow;
            await _context.SaveChangesAsync();

            return Ok(new
            {
                Success = true,
                Data = flashcard,
                Message = "Flashcard updated successfully"
            });
        }
        catch (UnauthorizedAccessException)
        {
            return Unauthorized(new { Success = false, Error = "Unauthorized" });
        }
        catch (Exception ex)
        {
            return StatusCode(500, new
            {
                Success = false,
                Error = "Failed to update flashcard",
                Timestamp = DateTime.UtcNow
            });
        }
    }

    [HttpDelete("{id}")]
    public async Task<ActionResult> DeleteFlashcard(Guid id)
    {
        try
        {
            var userId = GetUserId();

            var flashcard = await _context.Flashcards
                .FirstOrDefaultAsync(f => f.Id == id && f.UserId == userId);

            if (flashcard == null)
                return NotFound(new { Success = false, Error = "Flashcard not found" });

            _context.Flashcards.Remove(flashcard);
            await _context.SaveChangesAsync();

            return Ok(new
            {
                Success = true,
                Message = "Flashcard deleted successfully"
            });
        }
        catch (UnauthorizedAccessException)
        {
            return Unauthorized(new { Success = false, Error = "Unauthorized" });
        }
        catch (Exception ex)
        {
            return StatusCode(500, new
            {
                Success = false,
                Error = "Failed to delete flashcard",
                Timestamp = DateTime.UtcNow
            });
        }
    }

    [HttpPost("batch")]
    public async Task<ActionResult> BatchCreateFlashcards([FromBody] BatchCreateFlashcardsRequest request)
    {
        try
        {
            var userId = GetUserId();

            if (request.Cards == null || !request.Cards.Any())
                return BadRequest(new { Success = false, Error = "No cards provided" });

            if (request.Cards.Count > 50)
                return BadRequest(new { Success = false, Error = "Maximum 50 cards per batch" });

            // 確定要使用的卡組ID
            Guid cardSetId;
            if (request.CardSetId.HasValue)
            {
                var cardSet = await _context.CardSets
                    .FirstOrDefaultAsync(cs => cs.Id == request.CardSetId.Value && cs.UserId == userId);

                if (cardSet == null)
                    return NotFound(new { Success = false, Error = "Card set not found" });

                cardSetId = request.CardSetId.Value;
            }
            else
            {
                cardSetId = await GetOrCreateDefaultCardSetAsync(userId);
            }

            var savedCards = new List<object>();
            var errors = new List<string>();

            using var transaction = await _context.Database.BeginTransactionAsync();

            try
            {
                foreach (var cardRequest in request.Cards)
                {
                    try
                    {
                        var flashcard = new Flashcard
                        {
                            Id = Guid.NewGuid(),
                            UserId = userId,
                            CardSetId = cardSetId,
                            Word = cardRequest.Word.Trim(),
                            Translation = cardRequest.Translation.Trim(),
                            Definition = cardRequest.Definition.Trim(),
                            PartOfSpeech = cardRequest.PartOfSpeech?.Trim(),
                            Pronunciation = cardRequest.Pronunciation?.Trim(),
                            Example = cardRequest.Example?.Trim(),
                            ExampleTranslation = cardRequest.ExampleTranslation?.Trim()
                        };

                        _context.Flashcards.Add(flashcard);
                        savedCards.Add(new
                        {
                            Id = flashcard.Id,
                            Word = flashcard.Word,
                            Translation = flashcard.Translation
                        });
                    }
                    catch (Exception ex)
                    {
                        errors.Add($"Failed to save card '{cardRequest.Word}': {ex.Message}");
                    }
                }

                await _context.SaveChangesAsync();
                await transaction.CommitAsync();

                return Ok(new
                {
                    Success = true,
                    Data = new
                    {
                        SavedCards = savedCards,
                        SavedCount = savedCards.Count,
                        ErrorCount = errors.Count,
                        Errors = errors
                    },
                    Message = $"Successfully saved {savedCards.Count} flashcards"
                });
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync();
                throw;
            }
        }
        catch (UnauthorizedAccessException)
        {
            return Unauthorized(new { Success = false, Error = "Unauthorized" });
        }
        catch (Exception ex)
        {
            return StatusCode(500, new
            {
                Success = false,
                Error = "Failed to create flashcards",
                Timestamp = DateTime.UtcNow
            });
        }
    }
}

// DTOs
public class CreateFlashcardRequest
{
    public Guid? CardSetId { get; set; }
    public string Word { get; set; } = string.Empty;
    public string Translation { get; set; } = string.Empty;
    public string Definition { get; set; } = string.Empty;
    public string? PartOfSpeech { get; set; }
    public string? Pronunciation { get; set; }
    public string? Example { get; set; }
    public string? ExampleTranslation { get; set; }
}

public class UpdateFlashcardRequest
{
    public string? Word { get; set; }
    public string? Translation { get; set; }
    public string? Definition { get; set; }
    public string? PartOfSpeech { get; set; }
    public string? Pronunciation { get; set; }
    public string? Example { get; set; }
    public string? ExampleTranslation { get; set; }
    public bool? IsFavorite { get; set; }
}

public class BatchCreateFlashcardsRequest
{
    public Guid? CardSetId { get; set; }
    public List<CreateFlashcardRequest> Cards { get; set; } = new();
}