package tasks

import (
	"errors"
	"fmt"

	"gorm.io/gorm"
	"senlinai-agent/backend/internal/models"
)

type Service struct {
}

type LinkedObject struct {
	ObjectType string `json:"object_type"`
	ObjectID   uint   `json:"object_id"`
}

func NewService() *Service {
	return &Service{}
}

func (s *Service) Assign(taskID uint, assigneeID uint) error {
	return models.DBService.Transaction(func(tx *gorm.DB) error {
		var task models.SenlinAgentTask
		if err := tx.First(&task, taskID).Error; err != nil {
			return err
		}
		if err := tx.Model(&task).Update("assignee_id", assigneeID).Error; err != nil {
			return err
		}
		return tx.Create(&models.SenlinAgentProjectEvent{
			ProjectID:  task.ProjectID,
			ActorID:    task.CreatedBy,
			EventType:  "task_assigned",
			EntityType: "task",
			EntityID:   task.ID,
			Summary:    fmt.Sprintf("Task assigned to user %d", assigneeID),
		}).Error
	})
}

func (s *Service) ShareObject(taskID uint, objectType string, objectID uint) error {
	if objectType != "note" && objectType != "source" {
		return errors.New("unsupported shared object type")
	}
	return models.DBService.Transaction(func(tx *gorm.DB) error {
		var task models.SenlinAgentTask
		if err := tx.First(&task, taskID).Error; err != nil {
			return err
		}
		if err := ensureSharedObjectInProject(tx, task.ProjectID, objectType, objectID); err != nil {
			return err
		}
		if err := tx.Create(&models.SenlinAgentTaskShare{TaskID: taskID, ObjectType: objectType, ObjectID: objectID}).Error; err != nil {
			return err
		}
		return tx.Create(&models.SenlinAgentProjectEvent{
			ProjectID:  task.ProjectID,
			ActorID:    task.CreatedBy,
			EventType:  "task_object_shared",
			EntityType: "task",
			EntityID:   task.ID,
			Summary:    fmt.Sprintf("Shared %s %d with task", objectType, objectID),
		}).Error
	})
}

func (s *Service) VisibleLinkedObjects(taskID uint, viewerID uint) ([]LinkedObject, error) {
	var task models.SenlinAgentTask
	if err := models.DBService.First(&task, taskID).Error; err != nil {
		return nil, err
	}
	if task.AssigneeID == nil || *task.AssigneeID != viewerID {
		return []LinkedObject{}, nil
	}
	var shares []models.SenlinAgentTaskShare
	if err := models.DBService.Where("task_id = ?", taskID).Find(&shares).Error; err != nil {
		return nil, err
	}
	objects := make([]LinkedObject, 0, len(shares))
	for _, share := range shares {
		objects = append(objects, LinkedObject{ObjectType: share.ObjectType, ObjectID: share.ObjectID})
	}
	return objects, nil
}

func ensureSharedObjectInProject(tx *gorm.DB, projectID uint, objectType string, objectID uint) error {
	switch objectType {
	case "note":
		var count int64
		if err := tx.Model(&models.SenlinAgentNote{}).Where("id = ? AND project_id = ?", objectID, projectID).Count(&count).Error; err != nil {
			return err
		}
		if count == 0 {
			return errors.New("shared object not found in task project")
		}
	case "source":
		var count int64
		if err := tx.Model(&models.SenlinAgentSource{}).Where("id = ? AND project_id = ?", objectID, projectID).Count(&count).Error; err != nil {
			return err
		}
		if count == 0 {
			return errors.New("shared object not found in task project")
		}
	}
	return nil
}
