package mail

import (
	"context"
	"encoding/json"
	"errors"

	"github.com/jackc/pgx/v5"

	"github.com/ultisuite/ulti-backend/internal/mail/rules"
)

func (s *Service) SimulateRule(ctx context.Context, externalID string, req *simulateRuleRequest) (any, error) {
	msg := &rules.Message{
		ID:             "simulation",
		From:           req.Message.From,
		To:             req.Message.To,
		Subject:        req.Message.Subject,
		BodyText:       req.Message.BodyText,
		HasAttachments: req.Message.HasAttachments,
		Labels:         req.Message.Labels,
	}

	engine := rules.NewEngine(s.db)

	wf, conditions, actions, err := s.resolveSimulateRulePayload(ctx, externalID, req)
	if err != nil {
		return nil, err
	}

	if wf != nil && len(wf.Nodes) > 0 {
		var userID string
		_ = s.db.QueryRow(ctx, `SELECT id FROM users WHERE external_id = $1`, externalID).Scan(&userID)
		return engine.SimulateWorkflow(ctx, userID, wf, msg, &rules.EventContext{Type: rules.TriggerMessageReceived}), nil
	}

	return engine.SimulateRule(ctx, conditions, actions, msg), nil
}

func (s *Service) resolveSimulateRulePayload(ctx context.Context, externalID string, req *simulateRuleRequest) (*rules.Workflow, []rules.Condition, []rules.Action, error) {
	if req.RuleID != "" {
		var condJSON, actJSON, wfJSON []byte
		err := s.db.QueryRow(ctx, `
			SELECT conditions, actions, workflow
			FROM mail_rules
			WHERE id = $1 AND user_id = (SELECT id FROM users WHERE external_id = $2)
		`, req.RuleID, externalID).Scan(&condJSON, &actJSON, &wfJSON)
		if err != nil {
			if errors.Is(err, pgx.ErrNoRows) {
				return nil, nil, nil, ErrNotFound
			}
			return nil, nil, nil, err
		}
		wf, err := rules.ParseWorkflow(wfJSON)
		if err != nil {
			return nil, nil, nil, err
		}
		if wf != nil && len(wf.Nodes) > 0 {
			return wf, nil, nil, nil
		}
		conditions, actions, err := unmarshalRuleConditionsActions(condJSON, actJSON)
		return nil, conditions, actions, err
	}

	if req.Rule.Workflow != nil {
		wfJSON, err := json.Marshal(req.Rule.Workflow)
		if err != nil {
			return nil, nil, nil, err
		}
		wf, err := rules.ParseWorkflow(wfJSON)
		if err != nil {
			return nil, nil, nil, err
		}
		if wf != nil && len(wf.Nodes) > 0 {
			return wf, nil, nil, nil
		}
	}

	condJSON, err := json.Marshal(req.Rule.Conditions)
	if err != nil {
		return nil, nil, nil, err
	}
	actJSON, err := json.Marshal(req.Rule.Actions)
	if err != nil {
		return nil, nil, nil, err
	}
	conditions, actions, err := unmarshalRuleConditionsActions(condJSON, actJSON)
	return nil, conditions, actions, err
}

func unmarshalRuleConditionsActions(condJSON, actJSON []byte) ([]rules.Condition, []rules.Action, error) {
	var conditions []rules.Condition
	var actions []rules.Action
	if err := json.Unmarshal(condJSON, &conditions); err != nil {
		return nil, nil, err
	}
	if err := json.Unmarshal(actJSON, &actions); err != nil {
		return nil, nil, err
	}
	return conditions, actions, nil
}
