package store

import (
	"database/sql"
)

// Route is one "<service>_url" line attached to a sandbox. The agent
// pushes the whole set to the gateway by replacing any matching lines
// in the gateway's config.php.
type Route struct {
	ID        string `json:"id"`
	SandboxID string `json:"sandboxId"`
	Key       string `json:"key"`
	Value     string `json:"value"`
	TargetOCP bool   `json:"targetOcp"`
}

// SetRoutes atomically replaces the routing table for a sandbox. The
// gateway agent's "push" frame is the whole set.
func (s *Store) SetRoutes(sandboxID string, routes []Route) error {
	tx, err := s.db.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()
	if _, err := tx.Exec(`DELETE FROM routes WHERE sandbox_id=?`, sandboxID); err != nil {
		return err
	}
	for i := range routes {
		r := routes[i]
		r.SandboxID = sandboxID
		if r.ID == "" {
			r.ID = sandboxID + "-" + r.Key
		}
		if _, err := tx.Exec(
			`INSERT INTO routes(id, sandbox_id, key, value, target_ocp) VALUES(?,?,?,?,?)`,
			r.ID, r.SandboxID, r.Key, r.Value, boolInt(r.TargetOCP)); err != nil {
			return err
		}
	}
	return tx.Commit()
}

// ListRoutes returns the routes for one sandbox.
func (s *Store) ListRoutes(sandboxID string) ([]Route, error) {
	rows, err := s.db.Query(
		`SELECT id, sandbox_id, key, COALESCE(value,''), target_ocp
		 FROM routes WHERE sandbox_id=? ORDER BY key`, sandboxID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var out []Route
	for rows.Next() {
		var r Route
		var targetOCP int
		if err := rows.Scan(&r.ID, &r.SandboxID, &r.Key, &r.Value, &targetOCP); err != nil {
			return nil, err
		}
		r.TargetOCP = targetOCP == 1
		out = append(out, r)
	}
	return out, rows.Err()
}

// GetRoute returns one route by sandbox+key, or ErrNotFound.
func (s *Store) GetRoute(sandboxID, key string) (*Route, error) {
	row := s.db.QueryRow(
		`SELECT id, sandbox_id, key, COALESCE(value,''), target_ocp
		 FROM routes WHERE sandbox_id=? AND key=?`, sandboxID, key)
	var r Route
	var targetOCP int
	err := row.Scan(&r.ID, &r.SandboxID, &r.Key, &r.Value, &targetOCP)
	if err == sql.ErrNoRows {
		return nil, ErrNotFound
	}
	if err != nil {
		return nil, err
	}
	r.TargetOCP = targetOCP == 1
	return &r, nil
}
