package service

import (
	"context"
	"encoding/json"
	"time"

	taskbiz "kra/internal/biz/task"
	"kra/internal/service/dto"
)

type TaskService struct {
	uc *taskbiz.TaskApplicationUsecase
}

func NewTaskService(uc *taskbiz.TaskApplicationUsecase) *TaskService {
	return &TaskService{uc: uc}
}
func taskDomain(v *dto.TaskRequest) *taskbiz.TimedTask {
	return &taskbiz.TimedTask{ID: v.ID, Name: v.Name, Description: v.Description, Spec: v.Spec, WithSeconds: v.WithSeconds, ExecutorType: v.ExecutorType, MethodName: v.MethodName, Params: v.Params, HTTPURL: v.HTTPURL, HTTPMethod: v.HTTPMethod, HTTPHeader: v.HTTPHeader, HTTPBody: v.HTTPBody, HTTPAllowPrivate: v.HTTPAllowPrivate, Enabled: v.Enabled}
}
func (s *TaskService) CreateRequest(ctx context.Context, req *dto.TaskRequest) (uint, error) {
	value := taskDomain(req)
	if err := s.Create(ctx, value); err != nil {
		return 0, err
	}
	return value.ID, nil
}
func (s *TaskService) UpdateRequest(ctx context.Context, req *dto.TaskRequest) error {
	return s.Update(ctx, taskDomain(req))
}
func (s *TaskService) ListRequest(ctx context.Context, page, size int, name, executorType string, enabled *bool) ([]*dto.TaskResponse, int64, error) {
	return s.Tasks(ctx, page, size, &taskbiz.TimedTask{Name: name, ExecutorType: executorType, EnabledFilter: enabled})
}
func (s *TaskService) Create(ctx context.Context, v *taskbiz.TimedTask) error {
	return s.uc.Create(ctx, v)
}
func (s *TaskService) Update(ctx context.Context, v *taskbiz.TimedTask) error {
	return s.uc.Update(ctx, v)
}
func (s *TaskService) Delete(ctx context.Context, id uint) error {
	return s.uc.Delete(ctx, id)
}
func (s *TaskService) Toggle(ctx context.Context, id uint, enabled bool) error {
	return s.uc.Toggle(ctx, id, enabled)
}
func taskDTO(v *taskbiz.TimedTask, next *time.Time) *dto.TaskResponse {
	return &dto.TaskResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, Name: v.Name, Description: v.Description, Spec: v.Spec, WithSeconds: v.WithSeconds, ExecutorType: v.ExecutorType, MethodName: v.MethodName, Params: json.RawMessage(v.Params), HTTPURL: v.HTTPURL, HTTPMethod: v.HTTPMethod, HTTPHeader: json.RawMessage(v.HTTPHeader), HTTPBody: v.HTTPBody, HTTPAllowPrivate: v.HTTPAllowPrivate, Enabled: v.Enabled, NextRunAt: next}
}
func (s *TaskService) Tasks(ctx context.Context, page, size int, q *taskbiz.TimedTask) ([]*dto.TaskResponse, int64, error) {
	items, total, next, err := s.uc.List(ctx, page, size, q)
	if err != nil {
		return nil, 0, err
	}
	out := make([]*dto.TaskResponse, 0, len(items))
	for _, v := range items {
		var ptr *time.Time
		if value, ok := next[v.ID]; ok {
			copy := value
			ptr = &copy
		}
		out = append(out, taskDTO(v, ptr))
	}
	return out, total, nil
}

func (s *TaskService) Logs(ctx context.Context, page, size int, taskID uint, status string) ([]*dto.TaskLogResponse, int64, error) {
	items, total, err := s.uc.Logs(ctx, page, size, taskID, status)
	if err != nil {
		return nil, 0, err
	}
	out := make([]*dto.TaskLogResponse, 0, len(items))
	for _, v := range items {
		out = append(out, &dto.TaskLogResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, TaskID: v.TaskID, TaskName: v.TaskName, TriggerType: v.TriggerType, StartedAt: v.StartedAt, FinishedAt: v.FinishedAt, DurationMS: v.DurationMS, Status: v.Status, ErrorMsg: v.ErrorMsg, Output: v.Output})
	}
	return out, total, nil
}

func (s *TaskService) Trigger(ctx context.Context, id uint) error  { return s.uc.Trigger(ctx, id) }
func (s *TaskService) Reload(ctx context.Context) error            { return s.uc.Reload(ctx) }
func (s *TaskService) Subscribe(userID uint) chan []byte           { return s.uc.Subscribe(userID) }
func (s *TaskService) Unsubscribe(userID uint, events chan []byte) { s.uc.Unsubscribe(userID, events) }

func (s *TaskService) RegisteredMethods() []*dto.TaskMethodResponse {
	methods := s.uc.RegisteredMethods()
	out := make([]*dto.TaskMethodResponse, 0, len(methods))
	for _, method := range methods {
		out = append(out, &dto.TaskMethodResponse{Name: method.Name, Description: method.Description})
	}
	return out
}
