using DotNext;
using LinqToDB;
using LinqToDB.Data;

namespace Database;

public class ExamManager
{
    private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

    private readonly AppDataConnection _db;

    public ExamManager(AppDataConnection db)
    {
        this._db = db;
    }

    /// <summary>
    /// 创建新实验
    /// </summary>
    /// <param name="id">实验ID</param>
    /// <param name="name">实验名称</param>
    /// <param name="description">实验描述</param>
    /// <param name="tags">实验标签</param>
    /// <param name="difficulty">实验难度</param>
    /// <param name="isVisibleToUsers">普通用户是否可见</param>
    /// <returns>创建的实验</returns>
    public Result<Exam> CreateExam(string id, string name, string description, string[]? tags = null, int difficulty = 1, bool isVisibleToUsers = true)
    {
        try
        {
            // 检查实验ID是否已存在
            var existingExam = _db.ExamTable.Where(e => e.ID.ToString() == id).FirstOrDefault();
            if (existingExam != null)
            {
                logger.Error($"实验ID已存在: {id}");
                return new(new Exception($"实验ID已存在: {id}"));
            }

            var exam = new Exam
            {
                ID = id,
                Name = name,
                Description = description,
                Difficulty = Math.Max(1, Math.Min(5, difficulty)),
                IsVisibleToUsers = isVisibleToUsers,
                CreatedTime = DateTime.Now,
                UpdatedTime = DateTime.Now
            };

            if (tags != null)
            {
                exam.SetTagsList(tags);
            }

            _db.Insert(exam);
            logger.Info($"新实验已创建: {id} ({name})");
            return new(exam);
        }
        catch (Exception ex)
        {
            logger.Error($"创建实验时出错: {ex.Message}");
            return new(ex);
        }
    }

    /// <summary>
    /// 更新实验信息
    /// </summary>
    /// <param name="id">实验ID</param>
    /// <param name="name">实验名称</param>
    /// <param name="description">实验描述</param>
    /// <param name="tags">实验标签</param>
    /// <param name="difficulty">实验难度</param>
    /// <param name="isVisibleToUsers">普通用户是否可见</param>
    /// <returns>更新的记录数</returns>
    public Result<int> UpdateExam(string id, string? name = null, string? description = null, string[]? tags = null, int? difficulty = null, bool? isVisibleToUsers = null)
    {
        try
        {
            int result = 0;

            if (name != null)
            {
                result += _db.ExamTable.Where(e => e.ID.ToString() == id).Set(e => e.Name, name).Update();
            }
            if (description != null)
            {
                result += _db.ExamTable.Where(e => e.ID.ToString() == id).Set(e => e.Description, description).Update();
            }
            if (tags != null)
            {
                var tagsString = string.Join(",", tags.Where(tag => !string.IsNullOrWhiteSpace(tag)).Select(tag => tag.Trim()));
                result += _db.ExamTable.Where(e => e.ID.ToString() == id).Set(e => e.Tags, tagsString).Update();
            }
            if (difficulty.HasValue)
            {
                result += _db.ExamTable.Where(e => e.ID.ToString() == id).Set(e => e.Difficulty, Math.Max(1, Math.Min(5, difficulty.Value))).Update();
            }
            if (isVisibleToUsers.HasValue)
            {
                result += _db.ExamTable.Where(e => e.ID.ToString() == id).Set(e => e.IsVisibleToUsers, isVisibleToUsers.Value).Update();
            }

            // 更新时间
            _db.ExamTable.Where(e => e.ID.ToString() == id).Set(e => e.UpdatedTime, DateTime.Now).Update();

            logger.Info($"实验已更新: {id}，更新记录数: {result}");
            return new(result);
        }
        catch (Exception ex)
        {
            logger.Error($"更新实验时出错: {ex.Message}");
            return new(ex);
        }
    }

    /// <summary>
    /// 获取所有实验信息
    /// </summary>
    /// <returns>所有实验的数组</returns>
    public Exam[] GetAllExams()
    {
        var exams = _db.ExamTable.OrderBy(e => e.ID).ToArray();
        logger.Debug($"获取所有实验，共 {exams.Length} 个");
        return exams;
    }

    /// <summary>
    /// 根据实验ID获取实验信息
    /// </summary>
    /// <param name="examId">实验ID</param>
    /// <returns>包含实验信息的结果，如果未找到则返回空</returns>
    public Result<Optional<Exam>> GetExamByID(string examId)
    {
        var exams = _db.ExamTable.Where(exam => exam.ID.ToString() == examId).ToArray();

        if (exams.Length > 1)
        {
            logger.Error($"数据库中存在多个相同ID的实验: {examId}");
            return new(new Exception($"数据库中存在多个相同ID的实验: {examId}"));
        }

        if (exams.Length == 0)
        {
            logger.Info($"未找到ID对应的实验: {examId}");
            return new(Optional<Exam>.None);
        }

        logger.Debug($"成功获取实验信息: {examId}");
        return new(exams[0]);
    }

}
