package cron

import (
	"context"
	"fmt"
	"os"
	"time"

	"git.imall.cloud/openim/open-im-server-deploy/pkg/common/storage/model"
	"git.imall.cloud/openim/open-im-server-deploy/pkg/common/webhook"
	"github.com/openimsdk/tools/errs"
	"github.com/openimsdk/tools/log"
	"github.com/openimsdk/tools/mcontext"
)

// meetingPagination 简单的分页实现，供定时任务批量扫描使用
type meetingPagination struct {
	pageNumber int32
	showNumber int32
}

func (p *meetingPagination) GetPageNumber() int32 {
	if p.pageNumber <= 0 {
		return 1
	}
	return p.pageNumber
}

func (p *meetingPagination) GetShowNumber() int32 {
	if p.showNumber <= 0 {
		return 200
	}
	return p.showNumber
}

// dismissMeetingGroups 解散已结束超过10分钟的会议群聊
func (c *cronServer) dismissMeetingGroups() {
	now := time.Now()
	// 计算10分钟前的时间
	beforeTime := now.Add(-10 * time.Minute)
	operationID := fmt.Sprintf("cron_dismiss_meeting_groups_%d_%d", os.Getpid(), now.UnixMilli())
	ctx := mcontext.SetOperationID(c.ctx, operationID)

	log.ZDebug(ctx, "Start dismissing meeting groups", "beforeTime", beforeTime)

	// 先将已过期但状态仍为已预约/进行中的会议标记为已结束
	c.finishExpiredMeetings(ctx, now)

	// 查询已结束且结束时间在10分钟前的会议
	// 结束时间 = scheduledTime + duration（分钟）
	meetings, err := c.meetingDB.FindFinishedMeetingsBefore(ctx, beforeTime)
	if err != nil {
		log.ZError(ctx, "Failed to find finished meetings", err)
		return
	}

	if len(meetings) == 0 {
		log.ZDebug(ctx, "No finished meetings to dismiss groups")
		return
	}

	log.ZInfo(ctx, "Found finished meetings to dismiss groups", "count", len(meetings))

	dismissedCount := 0
	failedCount := 0

	for _, meeting := range meetings {
		if meeting.GroupID == "" {
			log.ZWarn(ctx, "Meeting has no group ID, skip", nil, "meetingID", meeting.MeetingID)
			continue
		}

		// 计算会议结束时间
		endTime := meeting.ScheduledTime.Add(time.Duration(meeting.Duration) * time.Minute)
		// 检查是否已经超过10分钟
		if now.Sub(endTime) < 10*time.Minute {
			log.ZDebug(ctx, "Meeting ended less than 10 minutes ago, skip", "meetingID", meeting.MeetingID, "endTime", endTime)
			continue
		}

		// 解散群聊，deleteMember设为true表示删除所有成员
		ctx := mcontext.SetOperationID(c.ctx, fmt.Sprintf("%s_%s", operationID, meeting.MeetingID))
		err := c.groupClient.DismissGroup(ctx, meeting.GroupID, true)
		if err != nil {
			// 如果群不存在或找不到群主（RecordNotFoundError），说明群可能已经被解散或数据不一致
			if errs.ErrRecordNotFound.Is(err) {
				log.ZWarn(ctx, "Group not found or owner not found, may already be dismissed, clear groupID", nil, "meetingID", meeting.MeetingID, "groupID", meeting.GroupID)
				// 清空groupID，避免下次重复处理
				if updateErr := c.meetingDB.Update(ctx, meeting.MeetingID, map[string]any{"group_id": ""}); updateErr != nil {
					log.ZWarn(ctx, "Failed to clear groupID after group not found", updateErr, "meetingID", meeting.MeetingID)
				}
				// 不增加失败计数，因为这不是真正的失败
				continue
			}
			log.ZError(ctx, "Failed to dismiss meeting group", err, "meetingID", meeting.MeetingID, "groupID", meeting.GroupID)
			failedCount++
			continue
		}

		// 从webhook配置的attentionIds中移除会议群ID
		if c.systemConfigDB != nil {
			if err := webhook.UpdateAttentionIds(ctx, c.systemConfigDB, meeting.GroupID, false); err != nil {
				log.ZWarn(ctx, "dismissMeetingGroups: failed to remove groupID from webhook attentionIds", err, "meetingID", meeting.MeetingID, "groupID", meeting.GroupID)
			}
		}

		// 解散群成功后，清空会议的groupID，避免下次重复处理
		if updateErr := c.meetingDB.Update(ctx, meeting.MeetingID, map[string]any{"group_id": ""}); updateErr != nil {
			log.ZWarn(ctx, "Failed to clear groupID after dismissing group", updateErr, "meetingID", meeting.MeetingID, "groupID", meeting.GroupID)
		} else {
			log.ZInfo(ctx, "Successfully dismissed meeting group and cleared groupID", "meetingID", meeting.MeetingID, "groupID", meeting.GroupID, "endTime", endTime)
		}
		dismissedCount++
	}

	log.ZInfo(ctx, "Finished dismissing meeting groups", "total", len(meetings), "dismissed", dismissedCount, "failed", failedCount, "duration", time.Since(now))
}

// finishExpiredMeetings 将已过结束时间的会议状态更新为已结束
func (c *cronServer) finishExpiredMeetings(ctx context.Context, now time.Time) {
	statuses := []int32{model.MeetingStatusScheduled, model.MeetingStatusOngoing}
	for _, status := range statuses {
		page := int32(1)
		for {
			total, meetings, err := c.meetingDB.FindByStatus(ctx, status, &meetingPagination{pageNumber: page, showNumber: 200})
			if err != nil {
				log.ZWarn(ctx, "finishExpiredMeetings: failed to list meetings", err, "status", status, "page", page)
				break
			}
			if len(meetings) == 0 {
				break
			}

			for _, meeting := range meetings {
				endTime := meeting.ScheduledTime.Add(time.Duration(meeting.Duration) * time.Minute)
				if now.After(endTime) {
					if err := c.meetingDB.UpdateStatus(ctx, meeting.MeetingID, model.MeetingStatusFinished); err != nil {
						log.ZWarn(ctx, "finishExpiredMeetings: failed to update status", err, "meetingID", meeting.MeetingID)
						continue
					}
					log.ZInfo(ctx, "finishExpiredMeetings: meeting marked finished", "meetingID", meeting.MeetingID, "endTime", endTime)
				}
			}

			// 分页结束条件
			if int64(page*200) >= total {
				break
			}
			page++
		}
	}
}
