package store

import (
	"database/sql"
	"errors"
	"fmt"

	"github.com/google/uuid"
)

// SetWorkloadEnv upserts a single env var for the workload. Uses
// (workload_id, key) as the natural key — duplicate keys collapse onto
// the same row instead of accumulating.
func (s *Store) SetWorkloadEnv(env WorkloadEnv) (WorkloadEnv, error) {
	if env.WorkloadID == "" || env.Key == "" {
		return WorkloadEnv{}, fmt.Errorf("workload_env: workload_id and key are required")
	}
	now := Now()
	if env.ID == "" {
		env.ID = uuid.New().String()
	}
	env.UpdatedAt = now

	// Try INSERT first; on UNIQUE violation, fall through to UPDATE so the
	// row's ID + created_at survive.
	_, err := s.db.Exec(
		`INSERT INTO workload_env (id, workload_id, key, value, encrypted, created_at, updated_at)
		 VALUES (?, ?, ?, ?, ?, ?, ?)
		 ON CONFLICT(workload_id, key) DO UPDATE SET
			value = excluded.value,
			encrypted = excluded.encrypted,
			updated_at = excluded.updated_at`,
		env.ID, env.WorkloadID, env.Key, env.Value, BoolToInt(env.Encrypted),
		now, now,
	)
	if err != nil {
		return WorkloadEnv{}, fmt.Errorf("upsert workload env: %w", err)
	}
	// Re-read so the caller gets the canonical row (ID may differ when
	// the conflict path took over an older row).
	row, err := s.getWorkloadEnvByKey(env.WorkloadID, env.Key)
	if err != nil {
		return WorkloadEnv{}, err
	}
	return row, nil
}

// ListWorkloadEnv returns every env var for a workload, ordered by key.
func (s *Store) ListWorkloadEnv(workloadID string) ([]WorkloadEnv, error) {
	rows, err := s.db.Query(
		`SELECT id, workload_id, key, value, encrypted, created_at, updated_at
		 FROM workload_env WHERE workload_id = ? ORDER BY key`, workloadID,
	)
	if err != nil {
		return nil, fmt.Errorf("query workload env: %w", err)
	}
	defer rows.Close()

	out := []WorkloadEnv{}
	for rows.Next() {
		env, err := scanWorkloadEnvRows(rows)
		if err != nil {
			return nil, err
		}
		out = append(out, env)
	}
	return out, rows.Err()
}

// DeleteWorkloadEnv removes one env var by ID.
func (s *Store) DeleteWorkloadEnv(id string) error {
	result, err := s.db.Exec(`DELETE FROM workload_env WHERE id = ?`, id)
	if err != nil {
		return fmt.Errorf("delete workload env: %w", err)
	}
	n, _ := result.RowsAffected()
	if n == 0 {
		return fmt.Errorf("workload env %s: %w", id, ErrNotFound)
	}
	return nil
}

// getWorkloadEnvByKey is the upsert's re-read helper.
func (s *Store) getWorkloadEnvByKey(workloadID, key string) (WorkloadEnv, error) {
	var env WorkloadEnv
	var enc int
	err := s.db.QueryRow(
		`SELECT id, workload_id, key, value, encrypted, created_at, updated_at
		 FROM workload_env WHERE workload_id = ? AND key = ?`, workloadID, key,
	).Scan(&env.ID, &env.WorkloadID, &env.Key, &env.Value, &enc,
		&env.CreatedAt, &env.UpdatedAt)
	if errors.Is(err, sql.ErrNoRows) {
		return WorkloadEnv{}, fmt.Errorf("workload env (%s,%s): %w", workloadID, key, ErrNotFound)
	}
	if err != nil {
		return WorkloadEnv{}, fmt.Errorf("query workload env: %w", err)
	}
	env.Encrypted = enc != 0
	return env, nil
}

func scanWorkloadEnvRows(rows *sql.Rows) (WorkloadEnv, error) {
	var env WorkloadEnv
	var enc int
	if err := rows.Scan(&env.ID, &env.WorkloadID, &env.Key, &env.Value, &enc,
		&env.CreatedAt, &env.UpdatedAt); err != nil {
		return WorkloadEnv{}, fmt.Errorf("scan workload env: %w", err)
	}
	env.Encrypted = enc != 0
	return env, nil
}
