package iace

import (
	"context"
	"fmt"
	"time"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5"
)

// ============================================================================
// Evidence Operations
// ============================================================================

// CreateEvidence creates a new evidence record
func (s *Store) CreateEvidence(ctx context.Context, evidence *Evidence) error {
	if evidence.ID == uuid.Nil {
		evidence.ID = uuid.New()
	}
	if evidence.CreatedAt.IsZero() {
		evidence.CreatedAt = time.Now().UTC()
	}

	_, err := s.pool.Exec(ctx, `
		INSERT INTO iace_evidence (
			id, project_id, mitigation_id, verification_plan_id,
			file_name, file_path, file_hash, file_size, mime_type,
			description, uploaded_by, created_at
		) VALUES (
			$1, $2, $3, $4,
			$5, $6, $7, $8, $9,
			$10, $11, $12
		)
	`,
		evidence.ID, evidence.ProjectID, evidence.MitigationID, evidence.VerificationPlanID,
		evidence.FileName, evidence.FilePath, evidence.FileHash, evidence.FileSize, evidence.MimeType,
		evidence.Description, evidence.UploadedBy, evidence.CreatedAt,
	)
	if err != nil {
		return fmt.Errorf("create evidence: %w", err)
	}

	return nil
}

// ListEvidence lists all evidence for a project
func (s *Store) ListEvidence(ctx context.Context, projectID uuid.UUID) ([]Evidence, error) {
	rows, err := s.pool.Query(ctx, `
		SELECT
			id, project_id, mitigation_id, verification_plan_id,
			file_name, file_path, file_hash, file_size, mime_type,
			description, uploaded_by, created_at
		FROM iace_evidence WHERE project_id = $1
		ORDER BY created_at DESC
	`, projectID)
	if err != nil {
		return nil, fmt.Errorf("list evidence: %w", err)
	}
	defer rows.Close()

	var evidence []Evidence
	for rows.Next() {
		var e Evidence

		err := rows.Scan(
			&e.ID, &e.ProjectID, &e.MitigationID, &e.VerificationPlanID,
			&e.FileName, &e.FilePath, &e.FileHash, &e.FileSize, &e.MimeType,
			&e.Description, &e.UploadedBy, &e.CreatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("list evidence scan: %w", err)
		}

		evidence = append(evidence, e)
	}

	return evidence, nil
}

// ============================================================================
// Verification Plan Operations
// ============================================================================

// CreateVerificationPlan creates a new verification plan
func (s *Store) CreateVerificationPlan(ctx context.Context, req CreateVerificationPlanRequest) (*VerificationPlan, error) {
	vp := &VerificationPlan{
		ID:                 uuid.New(),
		ProjectID:          req.ProjectID,
		HazardID:           req.HazardID,
		MitigationID:       req.MitigationID,
		Title:              req.Title,
		Description:        req.Description,
		AcceptanceCriteria: req.AcceptanceCriteria,
		Method:             req.Method,
		Status:             "planned",
		CreatedAt:          time.Now().UTC(),
		UpdatedAt:          time.Now().UTC(),
	}

	_, err := s.pool.Exec(ctx, `
		INSERT INTO iace_verification_plans (
			id, project_id, hazard_id, mitigation_id,
			title, description, acceptance_criteria, method,
			status, result, completed_at, completed_by,
			created_at, updated_at
		) VALUES (
			$1, $2, $3, $4,
			$5, $6, $7, $8,
			$9, $10, $11, $12,
			$13, $14
		)
	`,
		vp.ID, vp.ProjectID, vp.HazardID, vp.MitigationID,
		vp.Title, vp.Description, vp.AcceptanceCriteria, string(vp.Method),
		vp.Status, "", nil, uuid.Nil,
		vp.CreatedAt, vp.UpdatedAt,
	)
	if err != nil {
		return nil, fmt.Errorf("create verification plan: %w", err)
	}

	return vp, nil
}

// UpdateVerificationPlan updates a verification plan with a dynamic set of fields
func (s *Store) UpdateVerificationPlan(ctx context.Context, id uuid.UUID, updates map[string]interface{}) (*VerificationPlan, error) {
	if len(updates) == 0 {
		return s.getVerificationPlan(ctx, id)
	}

	query := "UPDATE iace_verification_plans SET updated_at = NOW()"
	args := []interface{}{id}
	argIdx := 2

	for key, val := range updates {
		switch key {
		case "title", "description", "acceptance_criteria", "result", "status":
			query += fmt.Sprintf(", %s = $%d", key, argIdx)
			args = append(args, val)
			argIdx++
		case "method":
			query += fmt.Sprintf(", method = $%d", argIdx)
			args = append(args, val)
			argIdx++
		}
	}

	query += " WHERE id = $1"

	_, err := s.pool.Exec(ctx, query, args...)
	if err != nil {
		return nil, fmt.Errorf("update verification plan: %w", err)
	}

	return s.getVerificationPlan(ctx, id)
}

// CompleteVerification marks a verification plan as completed
func (s *Store) CompleteVerification(ctx context.Context, id uuid.UUID, result string, completedBy string) error {
	now := time.Now().UTC()
	completedByUUID, err := uuid.Parse(completedBy)
	if err != nil {
		return fmt.Errorf("invalid completed_by UUID: %w", err)
	}

	_, err = s.pool.Exec(ctx, `
		UPDATE iace_verification_plans SET
			status = 'completed',
			result = $2,
			completed_at = $3,
			completed_by = $4,
			updated_at = $3
		WHERE id = $1
	`, id, result, now, completedByUUID)
	if err != nil {
		return fmt.Errorf("complete verification: %w", err)
	}

	return nil
}

// ListVerificationPlans lists all verification plans for a project
func (s *Store) ListVerificationPlans(ctx context.Context, projectID uuid.UUID) ([]VerificationPlan, error) {
	rows, err := s.pool.Query(ctx, `
		SELECT
			id, project_id, hazard_id, mitigation_id,
			title, description, acceptance_criteria, method,
			status, result, completed_at, completed_by,
			created_at, updated_at
		FROM iace_verification_plans WHERE project_id = $1
		ORDER BY created_at ASC
	`, projectID)
	if err != nil {
		return nil, fmt.Errorf("list verification plans: %w", err)
	}
	defer rows.Close()

	var plans []VerificationPlan
	for rows.Next() {
		var vp VerificationPlan
		var method string

		err := rows.Scan(
			&vp.ID, &vp.ProjectID, &vp.HazardID, &vp.MitigationID,
			&vp.Title, &vp.Description, &vp.AcceptanceCriteria, &method,
			&vp.Status, &vp.Result, &vp.CompletedAt, &vp.CompletedBy,
			&vp.CreatedAt, &vp.UpdatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("list verification plans scan: %w", err)
		}

		vp.Method = VerificationMethod(method)
		plans = append(plans, vp)
	}

	return plans, nil
}

// getVerificationPlan is a helper to fetch a single verification plan by ID
func (s *Store) getVerificationPlan(ctx context.Context, id uuid.UUID) (*VerificationPlan, error) {
	var vp VerificationPlan
	var method string

	err := s.pool.QueryRow(ctx, `
		SELECT
			id, project_id, hazard_id, mitigation_id,
			title, description, acceptance_criteria, method,
			status, result, completed_at, completed_by,
			created_at, updated_at
		FROM iace_verification_plans WHERE id = $1
	`, id).Scan(
		&vp.ID, &vp.ProjectID, &vp.HazardID, &vp.MitigationID,
		&vp.Title, &vp.Description, &vp.AcceptanceCriteria, &method,
		&vp.Status, &vp.Result, &vp.CompletedAt, &vp.CompletedBy,
		&vp.CreatedAt, &vp.UpdatedAt,
	)
	if err == pgx.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("get verification plan: %w", err)
	}

	vp.Method = VerificationMethod(method)
	return &vp, nil
}

// DeleteVerificationPlan deletes a verification plan by ID
func (s *Store) DeleteVerificationPlan(ctx context.Context, id uuid.UUID) error {
	_, err := s.pool.Exec(ctx, `DELETE FROM iace_verification_plans WHERE id = $1`, id)
	if err != nil {
		return fmt.Errorf("delete verification plan: %w", err)
	}
	return nil
}

// ============================================================================
// Reference Data Operations
// ============================================================================

// ListLifecyclePhases returns all 12 lifecycle phases with DE/EN labels
func (s *Store) ListLifecyclePhases(ctx context.Context) ([]LifecyclePhaseInfo, error) {
	rows, err := s.pool.Query(ctx, `
		SELECT id, label_de, label_en, sort_order
		FROM iace_lifecycle_phases
		ORDER BY sort_order ASC
	`)
	if err != nil {
		return nil, fmt.Errorf("list lifecycle phases: %w", err)
	}
	defer rows.Close()

	var phases []LifecyclePhaseInfo
	for rows.Next() {
		var p LifecyclePhaseInfo
		if err := rows.Scan(&p.ID, &p.LabelDE, &p.LabelEN, &p.Sort); err != nil {
			return nil, fmt.Errorf("list lifecycle phases scan: %w", err)
		}
		phases = append(phases, p)
	}
	return phases, nil
}

// ListRoles returns all affected person roles from the reference table
func (s *Store) ListRoles(ctx context.Context) ([]RoleInfo, error) {
	rows, err := s.pool.Query(ctx, `
		SELECT id, label_de, label_en, sort_order
		FROM iace_roles
		ORDER BY sort_order ASC
	`)
	if err != nil {
		return nil, fmt.Errorf("list roles: %w", err)
	}
	defer rows.Close()

	var roles []RoleInfo
	for rows.Next() {
		var r RoleInfo
		if err := rows.Scan(&r.ID, &r.LabelDE, &r.LabelEN, &r.Sort); err != nil {
			return nil, fmt.Errorf("list roles scan: %w", err)
		}
		roles = append(roles, r)
	}
	return roles, nil
}

// ListEvidenceTypes returns all evidence types from the reference table
func (s *Store) ListEvidenceTypes(ctx context.Context) ([]EvidenceTypeInfo, error) {
	rows, err := s.pool.Query(ctx, `
		SELECT id, category, label_de, label_en, sort_order
		FROM iace_evidence_types
		ORDER BY sort_order ASC
	`)
	if err != nil {
		return nil, fmt.Errorf("list evidence types: %w", err)
	}
	defer rows.Close()

	var types []EvidenceTypeInfo
	for rows.Next() {
		var e EvidenceTypeInfo
		if err := rows.Scan(&e.ID, &e.Category, &e.LabelDE, &e.LabelEN, &e.Sort); err != nil {
			return nil, fmt.Errorf("list evidence types scan: %w", err)
		}
		types = append(types, e)
	}
	return types, nil
}
