using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using QYZH.InteractiveMagazine.IService;

using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Dto.CheckIn;
using QYZH.InteractiveMagazine.Models.Dto.Compensation;
using QYZH.InteractiveMagazine.Models.Dto.Points;
using QYZH.InteractiveMagazine.Models.Entity;
using QYZH.InteractiveMagazine.Models.Enum;
using QYZH.InteractiveMagazine.Repository;
using SqlSugar;

namespace QYZH.InteractiveMagazine.Service;

public class UsersService(
    BaseRepository<Users> usersRepository,
    ILogger<UsersService> _logger,
    IPointsService pointsService,
    ICheckInService checkInService,
    ICompensationTaskService compensationTaskService,
    IUserJournalService userJournalService,
    IOperationLogService operationLogService) : BaseRepository<Users>, IUsersService
{
    /// <summary>
    /// 分页查询用户列表
    /// </summary>
    public async Task<BaseResponse<PageListModel<UsersOutput>>> GetListAsync(UsersQueryInput input)
    {
        var page = Queryable()
            .WhereIF(!string.IsNullOrEmpty(input.WxUserId), u => u.WxUserId.ToString() == input.WxUserId)
            .OrderBy(u => u.Id, OrderByType.Desc)
            .ToPage<Users, UsersOutput>(input);

        return BaseResponse<PageListModel<UsersOutput>>.Success(page);
    }

    /// <summary>
    /// 获取用户详情（仅基本信息）
    /// </summary>
    public async Task<BaseResponse<UserDetailOutput>> GetDetailAsync(long id)
    {
        var user = await GetByIdAsync<UsersOutput>(u => u.Id == id);
        if (user == null)
        {
            return BaseResponse<UserDetailOutput>.Fail("用户不存在");
        }

        return BaseResponse<UserDetailOutput>.Success(new UserDetailOutput
        {
            BasicInfo = user
        });
    }

    /// <summary>
    /// 分页查询用户积分记录
    /// </summary>
    public async Task<BaseResponse<PageListModel<PointsRecordOutput>>> GetUserPointsRecordsAsync(long userId, PointsRecordQueryInput input)
    {
        input.UserId = userId;
        var result = await pointsService.GetPointsRecordsAsync(input);
        return BaseResponse<PageListModel<PointsRecordOutput>>.Success(result);
    }

    /// <summary>
    /// 分页查询用户签到记录
    /// </summary>
    public async Task<BaseResponse<PageListModel<CheckInRecordOutput>>> GetUserCheckInRecordsAsync(long userId, PageQueryModel input)
    {
        RefAsync<int> total = 0;
        var records = await Context.Queryable<CheckInRecord>()
            .Where(r => r.UserId == userId && !r.IsDeleted)
            .OrderBy(r => r.CheckInDate, OrderByType.Desc)
            .Select(r => new CheckInRecordOutput
            {
                Id = (long)r.Id,
                CheckInDate = r.CheckInDate,
                CreatedAt = r.CreatedAt,
                ConsecutiveDays = r.ConsecutiveDays,
                PointsAwarded = r.PointsAwarded,
                GrowthPointsAwarded = r.GrowthPointsAwarded,
                Type = r.Type.ToString(),
                Status = r.Status.ToString()
            })
            .ToPageListAsync(input.PageIndex, input.PageSize, total);

        var page = new PageListModel<CheckInRecordOutput>(records, input.PageIndex, input.PageSize, total);
        return BaseResponse<PageListModel<CheckInRecordOutput>>.Success(page);
    }

    /// <summary>
    /// 分页查询用户补偿任务
    /// </summary>
    public async Task<BaseResponse<PageListModel<CompensationTaskOutput>>> GetUserCompensationTasksAsync(long userId, CompensationTaskQueryInput input)
    {
        RefAsync<int> total = 0;
        var tasks = await Context.Queryable<CompensationTask>()
            .Where(t => t.UserId == userId && !t.IsDeleted)
            .WhereIF(input.Status.HasValue, t => t.Status == (int)input.Status)
            .WhereIF(input.TaskType.HasValue, t => t.TaskType == (int)input.TaskType)
            .WhereIF(!string.IsNullOrEmpty(input.BusinessSource), t => t.BusinessSource == input.BusinessSource)
            .OrderBy(t => t.CreatedAt, OrderByType.Desc)
            .Select(t => new CompensationTaskOutput
            {
                Id = t.Id,
                TaskType = (CompensationTaskTypeEnum)t.TaskType,
                BusinessSource = t.BusinessSource,
                BusinessId = t.BusinessId,
                UserId = t.UserId,
                Payload = t.Payload,
                ErrorMessage = t.ErrorMessage,
                ErrorSource = t.ErrorSource,
                RetryCount = t.RetryCount,
                MaxRetries = t.MaxRetries,
                Status = (CompensationTaskStatusEnum)t.Status,
                ProcessedAt = t.ProcessedAt,
                ScheduledAt = t.ScheduledAt,
                ResultMessage = t.ResultMessage,
                CreatedAt = t.CreatedAt
            })
            .ToPageListAsync(input.PageIndex, input.PageSize, total);

        var page = new PageListModel<CompensationTaskOutput>(tasks, input.PageIndex, input.PageSize, total);
        return BaseResponse<PageListModel<CompensationTaskOutput>>.Success(page);
    }

    /// <summary>
    /// 分页查询用户期刊列表（含期刊详情）
    /// </summary>
    public async Task<BaseResponse<PageListModel<UserJournalItemOutput>>> GetUserJournalsAsync(long userId, UserJournalQueryInput input)
    {
        RefAsync<int> total = 0;
        var items = await Context.Queryable<UserJournal>()
            .Where(uj => uj.UserId == userId && !uj.IsDeleted)
            .WhereIF(!string.IsNullOrWhiteSpace(input.Type), uj => uj.Type.ToString() == input.Type)
            .OrderByDescending(uj => uj.CreatedAt)
            .Select(uj => new UserJournalItemOutput
            {
                BindId = uj.Id,
                JournalId = uj.JournalId,
                Type = uj.Type.ToString(),
                Status = uj.Status.ToString(),
                CreatedAt = uj.CreatedAt
            })
            .ToPageListAsync(input.PageIndex, input.PageSize, total);

        // 填充期刊详情（标题、封面）
        var journalIds = items.Select(i => i.JournalId).Distinct().ToList();
        if (journalIds.Count > 0)
        {
            var journals = await Context.Queryable<Journal>()
                .Where(j => journalIds.Contains(j.Id) && !j.IsDeleted)
                .ToListAsync();
            var journalDict = journals.ToDictionary(j => j.Id);
            foreach (var item in items)
            {
                if (journalDict.TryGetValue(item.JournalId, out var journal))
                {
                    item.Name = journal.Name;
                    item.CoverImageUrl = journal.Cover;
                }
            }
        }

        var page = new PageListModel<UserJournalItemOutput>(items, input.PageIndex, input.PageSize, total);
        return BaseResponse<PageListModel<UserJournalItemOutput>>.Success(page);
    }

    /// <summary>
    /// 更新用户状态
    /// </summary>
    public async Task<BaseResponse> UpdateStatusAsync(long id)
    {
        var exists = await usersRepository.GetByIdAsync(id);
        if (exists == null)
        {
            return BaseResponse.Fail("用户不存在");
        }
        var statusValue = exists.Status == (int)UserStatusEnum.Active ? UserStatusEnum.Disabled : UserStatusEnum.Active;
        var result = await UpdateAsync(
            u => new Users { Status = (int)statusValue },
            u => u.Id == id
        );

        return result ? BaseResponse.Success() : BaseResponse.Fail("更新失败");
    }

    /// <summary>
    /// 手动增加用户积分
    /// </summary>
    public async Task<ManualPointsOutput> ManualAddPointsAsync(long userId, ManualAddPointsInput input, long operatorId, string operatorName, string? ipAddress = null)
    {
        _logger.LogInformation("管理员手动增加积分，UserId: {UserId}, Amount: {Amount}, Operator: {Operator}",
            userId, input.Amount, operatorName);

        // 校验用户是否存在
        var user = await Queryable().Where(u => u.Id == userId && !u.IsDeleted).FirstAsync();
        if (user == null)
            throw new BusinessException("用户不存在", ResultCode.NOT_FOUND);

        // 调用积分服务增加积分
        var result = await pointsService.AddPointsAsync(new AddPointsInput
        {
            UserId = userId,
            Amount = input.Amount,
            ChangeType = PointsChangeTypeEnum.ManualAdjust,
            Description = $"管理员手动增加: {input.Reason}",
            OperatorName = operatorName
        });

        // 记录操作日志
        var detail = JsonConvert.SerializeObject(new
        {
            Amount = input.Amount,
            Reason = input.Reason,
            PreviousBalance = result.PreviousBalance,
            NewBalance = result.NewBalance,
            RecordId = result.RecordId
        });

        await operationLogService.LogAsync(
            operatorId, operatorName,
            OperationLogActionType.ManualAddPoints,
            OperationLogTargetType.User,
            userId, user.Name, detail, ipAddress);

        return new ManualPointsOutput
        {
            RecordId = result.RecordId,
            PreviousBalance = result.PreviousBalance,
            NewBalance = result.NewBalance,
            ChangeAmount = input.Amount,
            OperatorName = operatorName,
            OperatedAt = DateTime.Now
        };
    }

    /// <summary>
    /// 手动扣除用户积分
    /// </summary>
    public async Task<ManualPointsOutput> ManualDeductPointsAsync(long userId, ManualDeductPointsInput input, long operatorId, string operatorName, string? ipAddress = null)
    {
        _logger.LogInformation("管理员手动扣除积分，UserId: {UserId}, Amount: {Amount}, Operator: {Operator}",
            userId, input.Amount, operatorName);

        // 校验用户是否存在
        var user = await Queryable().Where(u => u.Id == userId && !u.IsDeleted).FirstAsync();
        if (user == null)
            throw new BusinessException("用户不存在", ResultCode.NOT_FOUND);

        // 调用积分服务扣除积分
        var result = await pointsService.DeductPointsAsync(new DeductPointsInput
        {
            UserId = userId,
            Amount = input.Amount,
            ChangeType = PointsChangeTypeEnum.ManualAdjust,
            Description = $"管理员手动扣除: {input.Reason}",
            OperatorName = operatorName
        });

        // 记录操作日志
        var detail = JsonConvert.SerializeObject(new
        {
            Amount = input.Amount,
            Reason = input.Reason,
            PreviousBalance = result.PreviousBalance,
            NewBalance = result.NewBalance,
            RecordId = result.RecordId
        });

        await operationLogService.LogAsync(
            operatorId, operatorName,
            OperationLogActionType.ManualDeductPoints,
            OperationLogTargetType.User,
            userId, user.Name, detail, ipAddress);

        return new ManualPointsOutput
        {
            RecordId = result.RecordId,
            PreviousBalance = result.PreviousBalance,
            NewBalance = result.NewBalance,
            ChangeAmount = -input.Amount,
            OperatorName = operatorName,
            OperatedAt = DateTime.Now
        };
    }
}
