package store

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

	"github.com/google/uuid"
)

// CreateStageEnv inserts a new stage environment variable override.
func (s *Store) CreateStageEnv(env StageEnv) (StageEnv, error) {
	env.ID = uuid.New().String()
	env.CreatedAt = Now()
	env.UpdatedAt = env.CreatedAt

	_, err := s.db.Exec(
		`INSERT INTO stage_env (id, stage_id, key, value, encrypted, created_at, updated_at)
		 VALUES (?, ?, ?, ?, ?, ?, ?)`,
		env.ID, env.StageID, env.Key, env.Value, BoolToInt(env.Encrypted),
		env.CreatedAt, env.UpdatedAt,
	)
	if err != nil {
		return StageEnv{}, fmt.Errorf("insert stage env: %w", err)
	}
	return env, nil
}

// GetStageEnvByStageID returns all environment variable overrides for a stage.
func (s *Store) GetStageEnvByStageID(stageID string) ([]StageEnv, error) {
	rows, err := s.db.Query(
		`SELECT id, stage_id, key, value, encrypted, created_at, updated_at
		 FROM stage_env WHERE stage_id = ? ORDER BY key`, stageID,
	)
	if err != nil {
		return nil, fmt.Errorf("query stage env: %w", err)
	}
	defer rows.Close()

	envs := []StageEnv{}
	for rows.Next() {
		env, err := scanStageEnv(rows)
		if err != nil {
			return nil, err
		}
		envs = append(envs, env)
	}
	return envs, rows.Err()
}

// GetStageEnvByID returns a single stage env override by ID.
func (s *Store) GetStageEnvByID(id string) (StageEnv, error) {
	var env StageEnv
	var encrypted int
	err := s.db.QueryRow(
		`SELECT id, stage_id, key, value, encrypted, created_at, updated_at
		 FROM stage_env WHERE id = ?`, id,
	).Scan(&env.ID, &env.StageID, &env.Key, &env.Value, &encrypted,
		&env.CreatedAt, &env.UpdatedAt)
	if errors.Is(err, sql.ErrNoRows) {
		return StageEnv{}, fmt.Errorf("stage env %s: %w", id, ErrNotFound)
	}
	if err != nil {
		return StageEnv{}, fmt.Errorf("query stage env: %w", err)
	}
	env.Encrypted = encrypted != 0
	return env, nil
}

// UpdateStageEnv updates an existing stage environment variable override.
func (s *Store) UpdateStageEnv(env StageEnv) error {
	env.UpdatedAt = Now()
	result, err := s.db.Exec(
		`UPDATE stage_env SET key=?, value=?, encrypted=?, updated_at=?
		 WHERE id=?`,
		env.Key, env.Value, BoolToInt(env.Encrypted), env.UpdatedAt, env.ID,
	)
	if err != nil {
		return fmt.Errorf("update stage env: %w", err)
	}
	n, _ := result.RowsAffected()
	if n == 0 {
		return fmt.Errorf("stage env %s: %w", env.ID, ErrNotFound)
	}
	return nil
}

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

// scanStageEnv scans a stage env row from a *sql.Rows cursor.
func scanStageEnv(rows *sql.Rows) (StageEnv, error) {
	var env StageEnv
	var encrypted int
	err := rows.Scan(&env.ID, &env.StageID, &env.Key, &env.Value, &encrypted,
		&env.CreatedAt, &env.UpdatedAt)
	if err != nil {
		return StageEnv{}, fmt.Errorf("scan stage env: %w", err)
	}
	env.Encrypted = encrypted != 0
	return env, nil
}
