package mail

import (
	"context"

	"github.com/ultisuite/ulti-backend/internal/api/query"
	"github.com/ultisuite/ulti-backend/internal/securityaudit"
)

type UserLabelsList struct {
	Labels     []map[string]any     `json:"labels"`
	Pagination query.PaginationMeta `json:"pagination,omitempty"`
}

func (s *Service) ListUserLabels(ctx context.Context, externalID string, params query.ListParams) (UserLabelsList, error) {
	var total int64
	err := s.db.QueryRow(ctx, `
		SELECT COUNT(*) FROM mail_user_labels
		WHERE user_id = (SELECT id FROM users WHERE external_id = $1)
	`, externalID).Scan(&total)
	if err != nil {
		return UserLabelsList{}, err
	}

	rows, err := s.db.Query(ctx, `
		SELECT id, name, color, sort_order, created_at
		FROM mail_user_labels
		WHERE user_id = (SELECT id FROM users WHERE external_id = $1)
		ORDER BY sort_order ASC, name ASC
		LIMIT $2 OFFSET $3
	`, externalID, params.Limit(), params.Offset())
	if err != nil {
		return UserLabelsList{}, err
	}
	defer rows.Close()

	labels := make([]map[string]any, 0)
	for rows.Next() {
		var id, name, color string
		var sortOrder int
		var createdAt any
		if err := rows.Scan(&id, &name, &color, &sortOrder, &createdAt); err != nil {
			return UserLabelsList{}, err
		}
		labels = append(labels, map[string]any{
			"id": id, "name": name, "color": color, "sort_order": sortOrder, "created_at": createdAt,
		})
	}
	if err := rows.Err(); err != nil {
		return UserLabelsList{}, err
	}

	return UserLabelsList{
		Labels:     labels,
		Pagination: params.Meta(&total),
	}, nil
}

func (s *Service) CreateUserLabel(ctx context.Context, externalID string, req *createUserLabelRequest) (string, error) {
	var id string
	err := s.db.QueryRow(ctx, `
		WITH next_order AS (
			SELECT COALESCE(MAX(sort_order), -10) + 10 AS sort_order
			FROM mail_user_labels
			WHERE user_id = (SELECT id FROM users WHERE external_id = $1)
		)
		INSERT INTO mail_user_labels (user_id, name, color, sort_order)
		SELECT (SELECT id FROM users WHERE external_id = $1), $2, $3, next_order.sort_order
		FROM next_order
		RETURNING id
	`, externalID, req.Name, req.Color).Scan(&id)
	if err != nil {
		if isUniqueViolation(err) {
			return "", ErrDuplicateLabel
		}
		return "", err
	}
	return id, nil
}

func (s *Service) UpdateUserLabel(ctx context.Context, externalID, labelID string, req *updateUserLabelRequest) error {
	result, err := s.db.Exec(ctx, `
		UPDATE mail_user_labels SET name = $1, color = $2
		WHERE id = $3 AND user_id = (SELECT id FROM users WHERE external_id = $4)
	`, req.Name, req.Color, labelID, externalID)
	if err != nil {
		if isUniqueViolation(err) {
			return ErrDuplicateLabel
		}
		return err
	}
	if result.RowsAffected() == 0 {
		return ErrNotFound
	}
	return nil
}

func (s *Service) DeleteUserLabel(ctx context.Context, externalID, labelID string) error {
	result, err := s.db.Exec(ctx, `
		DELETE FROM mail_user_labels
		WHERE id = $1 AND user_id = (SELECT id FROM users WHERE external_id = $2)
	`, labelID, externalID)
	if err != nil {
		return err
	}
	if result.RowsAffected() == 0 {
		return ErrNotFound
	}
	if s.audit != nil {
		s.audit.Log(ctx, externalID, securityaudit.ActionCriticalDeletion, map[string]any{
			"target": "mail_user_label", "label_id": labelID,
		})
	}
	return nil
}
