package core

import (
	"context"
	"fmt"
	"intent-system/pkg/dal/dao"
	"sync"
	"time"

	"github.com/civet148/log"
	"github.com/gorilla/websocket"
)

type DeployTaskCore struct {
	AppID    string
	TarPath  string
	Progress int
	Status   string
	Err      error

	Ctx    context.Context
	Cancel context.CancelFunc

	Clients   map[*websocket.Conn]string
	Lock      sync.RWMutex
	DeployDAO *dao.DeployDAO
	UserName  string
	RepoName  string
	MbUuid    string
}

var GlobalTaskManager = &TaskManager{
	tasks: make(map[string]*DeployTaskCore),
}

type TaskManager struct {
	tasks map[string]*DeployTaskCore
	lock  sync.RWMutex
}

// ✅ 改为接收 tarPath
func (m *TaskManager) Create(appID string, tarPath string, deployDAO *dao.DeployDAO, userName string, repoName string, mbUuid string) *DeployTaskCore {
	m.lock.Lock()
	defer m.lock.Unlock()

	if _, exists := m.tasks[appID]; exists {
		log.Infof("重复任务，退出！")
		return nil
	}

	ctx, cancel := context.WithCancel(context.Background())
	task := &DeployTaskCore{
		AppID:     appID,
		TarPath:   tarPath, // ✅ 保存 tar 路径
		Ctx:       ctx,
		Cancel:    cancel,
		Clients:   make(map[*websocket.Conn]string),
		DeployDAO: deployDAO, // ✅ 注入 DAO
		UserName:  userName,  // ✅ 保存进结构体
		RepoName:  repoName,  // ✅ 保存进结构体
		MbUuid:    mbUuid,    // ✅ 保存进结构体
	}

	m.tasks[appID] = task
	go task.Run()
	return task
}

func (m *TaskManager) Get(appID string) *DeployTaskCore {
	m.lock.RLock()
	defer m.lock.RUnlock()
	return m.tasks[appID]
}

func (m *TaskManager) Remove(appID string) {
	m.lock.Lock()
	defer m.lock.Unlock()
	delete(m.tasks, appID)
}

func (t *DeployTaskCore) Run() {
	defer GlobalTaskManager.Remove(t.AppID)

	// ====== 等待数据库有四元组记录再继续 ======
	const maxWait = 30 // 最多等30秒
	waited := 0
	for {
		count, err := t.DeployDAO.CountByUserRepoUUIDAndStatus(t.UserName, t.RepoName, t.MbUuid, "deploying")
		if err != nil {
			log.Errorf("查询部署记录数量失败: %v", err)
			// 你可以选择直接 return，或者 continue 重试，或者 sleep 一下后重试
			// 这里建议直接 return，如果查 count 都报错，那后续也不用等了
			return
		}

		if count > 0 {
			break // 数据库已有记录，可以继续执行后续流程
		}
		if waited >= maxWait {
			t.Err = fmt.Errorf("等待超时，仍未发现deploying记录")
			t.broadcast([]byte("[DeployTaskCore Error] 等待超时，未检测到deploying记录"))
			return
		}
		time.Sleep(time.Second)
		waited++
	}

	// ✅ 失败清理逻辑，在任务退出前执行
	defer func() {
		if t.Err != nil {
			log.Warnf("部署失败，删除四元组记录：user_name=%s repo_name=%s mb_uuid=%s status=deploying", t.UserName, t.RepoName, t.MbUuid)
			err := t.DeployDAO.DeleteByUserRepoUUIDAndStatus(t.UserName, t.RepoName, t.MbUuid, "deploying")
			if err != nil {
				log.Errorf("清理失败部署记录时出错: %v", err)
			}
		}
	}()

	t.updateProgress(5, "5%")

	// Deploy using tar file
	containerID, err := DeployFromTarWithProgress(t.Ctx, t.TarPath, func(p int, phase string) {
		t.updateProgress(p, phase)
	})

	if err != nil {
		t.Lock.Lock()
		t.Status = "deployment_failed"
		t.Err = err
		t.Lock.Unlock()
		t.broadcast([]byte(fmt.Sprintf("[Deployment Failed] %v", err)))
		return
	}

	t.updateProgress(100, "100%")

	// Update deployment status in database
	err = t.DeployDAO.UpdateStatusByAppID(int64(mustParseAppID(t.AppID)), "running")
	if err != nil {
		log.Warnf("failed to update status to 'running' (appID=%v): %v", t.AppID, err)
	}

	t.broadcast([]byte("[Deployment Successful] Container ID: " + containerID))
}

func (t *DeployTaskCore) updateProgress(p int, status string) {
	t.Lock.Lock()
	t.Progress = p
	t.Status = status
	t.Lock.Unlock()
	t.broadcast([]byte(status)) // 只广播纯百分比字符串
}

func (t *DeployTaskCore) broadcast(msg []byte) {
	t.Lock.RLock()
	defer t.Lock.RUnlock()

	log.Infof("📤 Broadcasting message to %d clients: %s", len(t.Clients), msg)

	for conn, username := range t.Clients {
		prefix := fmt.Sprintf("[User %s] ", username)
		_ = conn.WriteMessage(websocket.TextMessage, []byte(prefix+string(msg)))
	}
}

func (t *DeployTaskCore) Attach(conn *websocket.Conn, username string) {
	t.Lock.Lock()
	defer t.Lock.Unlock()

	t.Clients[conn] = username
	log.Infof("用户 %s 连接部署任务 %s", username, t.AppID)
}

func (t *DeployTaskCore) Detach(conn *websocket.Conn) {
	t.Lock.Lock()
	username := t.Clients[conn]
	delete(t.Clients, conn)
	t.Lock.Unlock()

	_ = conn.Close()
	log.Infof("用户 %s 断开部署任务 %s 的连接", username, t.AppID)
}
