package services

import (
	"context"
	"fmt"

	"github.com/google/uuid"
	"github.com/jmoiron/sqlx"

	"mgit.msbls.de/m/KanzlAI-mGMT/internal/models"
)

type CaseAssignmentService struct {
	db *sqlx.DB
}

func NewCaseAssignmentService(db *sqlx.DB) *CaseAssignmentService {
	return &CaseAssignmentService{db: db}
}

// ListByCase returns all assignments for a case.
func (s *CaseAssignmentService) ListByCase(ctx context.Context, tenantID, caseID uuid.UUID) ([]models.CaseAssignment, error) {
	var assignments []models.CaseAssignment
	err := s.db.SelectContext(ctx, &assignments,
		`SELECT ca.id, ca.case_id, ca.user_id, ca.role, ca.assigned_at
		 FROM case_assignments ca
		 JOIN cases c ON c.id = ca.case_id
		 WHERE ca.case_id = $1 AND c.tenant_id = $2
		 ORDER BY ca.assigned_at`,
		caseID, tenantID)
	if err != nil {
		return nil, fmt.Errorf("list case assignments: %w", err)
	}
	return assignments, nil
}

// Assign adds a user to a case with the given role.
func (s *CaseAssignmentService) Assign(ctx context.Context, tenantID, caseID, userID uuid.UUID, role string) (*models.CaseAssignment, error) {
	// Verify user is a member of this tenant
	var memberExists bool
	err := s.db.GetContext(ctx, &memberExists,
		`SELECT EXISTS(SELECT 1 FROM user_tenants WHERE user_id = $1 AND tenant_id = $2)`,
		userID, tenantID)
	if err != nil {
		return nil, fmt.Errorf("check membership: %w", err)
	}
	if !memberExists {
		return nil, fmt.Errorf("user is not a member of this tenant")
	}

	// Verify case belongs to tenant
	var caseExists bool
	err = s.db.GetContext(ctx, &caseExists,
		`SELECT EXISTS(SELECT 1 FROM cases WHERE id = $1 AND tenant_id = $2)`,
		caseID, tenantID)
	if err != nil {
		return nil, fmt.Errorf("check case: %w", err)
	}
	if !caseExists {
		return nil, fmt.Errorf("case not found")
	}

	var assignment models.CaseAssignment
	err = s.db.QueryRowxContext(ctx,
		`INSERT INTO case_assignments (case_id, user_id, role)
		 VALUES ($1, $2, $3)
		 ON CONFLICT (case_id, user_id) DO UPDATE SET role = EXCLUDED.role
		 RETURNING id, case_id, user_id, role, assigned_at`,
		caseID, userID, role,
	).StructScan(&assignment)
	if err != nil {
		return nil, fmt.Errorf("assign user to case: %w", err)
	}
	return &assignment, nil
}

// Unassign removes a user from a case.
func (s *CaseAssignmentService) Unassign(ctx context.Context, tenantID, caseID, userID uuid.UUID) error {
	result, err := s.db.ExecContext(ctx,
		`DELETE FROM case_assignments ca
		 USING cases c
		 WHERE ca.case_id = c.id AND ca.case_id = $1 AND ca.user_id = $2 AND c.tenant_id = $3`,
		caseID, userID, tenantID)
	if err != nil {
		return fmt.Errorf("unassign: %w", err)
	}
	rows, _ := result.RowsAffected()
	if rows == 0 {
		return fmt.Errorf("assignment not found")
	}
	return nil
}
