class Kitsune::Kit::Commands::SetupPostgresDocker

def build_database_url(filled_options, postgres_defaults)

def build_database_url(filled_options, postgres_defaults)
  user = postgres_defaults[:postgres_user]
  password = postgres_defaults[:postgres_password]
  host = filled_options[:server_ip]
  port = postgres_defaults[:postgres_port]
  db = postgres_defaults[:postgres_db]
  "postgres://#{user}:#{password}@#{host}:#{port}/#{db}"
end

def create

def create
  postgres_defaults = Kitsune::Kit::Defaults.postgres
  if postgres_defaults[:postgres_password] == "secret"
    say "โš ๏ธ Warning: You are using the default PostgreSQL password ('secret').", :yellow
    if ENV.fetch("KIT_ENV", "development") == "production"
      abort "โŒ Production environment requires a secure PostgreSQL password!"
    else
      say "๐Ÿ”’ Please change POSTGRES_PASSWORD in your .env if needed.", :yellow
    end
  end
  filled_options = Kitsune::Kit::OptionsBuilder.build(
    options,
    required: [:server_ip],
    defaults: Kitsune::Kit::Defaults.ssh
  )
  with_ssh_connection(filled_options) do |ssh|
    perform_setup(ssh, postgres_defaults)
    database_url = build_database_url(filled_options, postgres_defaults)
    say "๐Ÿ”— Your DATABASE_URL is:\t", :cyan
    say database_url, :green
  end
end

def perform_rollback(ssh, postgres_defaults)

def perform_rollback(ssh, postgres_defaults)
  output = ssh.exec! <<~EOH
    set -e
    BASE_DIR="$HOME/docker/postgres"
    BACKUP_DIR="/usr/local/backups"
    SCRIPT_ID="setup_postgres_docker"
    AFTER_FILE="${BACKUP_DIR}/${SCRIPT_ID}.after"
    if [ -f "$AFTER_FILE" ]; then
      echo "๐Ÿ” Stopping and removing docker containers..."
      cd "$BASE_DIR"
      docker compose down -v || true
      echo "๐Ÿงน Cleaning up files..."
      rm -rf "$BASE_DIR"
      sudo rm -f "$AFTER_FILE"
      if command -v ufw >/dev/null; then
        echo "๐Ÿ›ก๏ธ Removing PostgreSQL port from firewall..."
        sudo ufw delete allow #{postgres_defaults[:postgres_port]} || true
      fi
    else
      echo "๐Ÿ’ก Nothing to rollback"
    fi
    echo "โœ… Rollback completed"
  EOH
  say output
end

def perform_setup(ssh, postgres_defaults)

def perform_setup(ssh, postgres_defaults)
  docker_compose_local = ".kitsune/docker/postgres.yml"
  unless File.exist?(docker_compose_local)
    say "โŒ Docker compose file not found at #{docker_compose_local}.", :red
    exit(1)
  end
  docker_dir_remote = "$HOME/docker/postgres"
  docker_compose_remote = "#{docker_dir_remote}/docker-compose.yml"
  docker_env_remote = "#{docker_dir_remote}/.env"
  backup_marker = "/usr/local/backups/setup_postgres_docker.after"
  # 1. Create base directory securely
  ssh.exec!("mkdir -p #{docker_dir_remote}")
  ssh.exec!("chmod 700 #{docker_dir_remote}")
  # 2. Upload docker-compose.yml
  say "๐Ÿ“ฆ Uploading docker-compose.yml to remote server...", :cyan
  content_compose = File.read(docker_compose_local)
  upload_file(ssh, content_compose, docker_compose_remote)
  # 3. Create .env file for docker-compose based on postgres_defaults
  say "๐Ÿ“ฆ Creating .env file for Docker Compose...", :cyan
  env_content = <<~ENVFILE
    POSTGRES_DB=#{postgres_defaults[:postgres_db]}
    POSTGRES_USER=#{postgres_defaults[:postgres_user]}
    POSTGRES_PASSWORD=#{postgres_defaults[:postgres_password]}
    POSTGRES_PORT=#{postgres_defaults[:postgres_port]}
    POSTGRES_IMAGE=#{postgres_defaults[:postgres_image]}
  ENVFILE
  upload_file(ssh, env_content, docker_env_remote)
  # 4. Secure file permissions
  ssh.exec!("chmod 600 #{docker_compose_remote} #{docker_env_remote}")
  # 5. Create backup marker
  ssh.exec!("sudo mkdir -p /usr/local/backups && sudo touch #{backup_marker}")
  # 6. Validate docker-compose.yml
  say "๐Ÿ” Validating docker-compose.yml...", :cyan
  validation_output = ssh.exec!("cd #{docker_dir_remote} && docker compose config")
  say validation_output, :cyan
  # 7. Check if container is running
  container_status = ssh.exec!("docker ps --filter 'name=postgres' --format '{{.Status}}'").strip
  if container_status.empty?
    say "โ–ถ๏ธ No running container. Running docker compose up...", :cyan
    ssh.exec!("cd #{docker_dir_remote} && docker compose up -d")
  else
    say "โš ๏ธ PostgreSQL container is already running.", :yellow
    if yes?("๐Ÿ” Recreate the container with updated configuration? [y/N]", :yellow)
      say "๐Ÿ”„ Recreating container...", :cyan
      ssh.exec!("cd #{docker_dir_remote} && docker compose down -v && docker compose up -d")
    else
      say "โฉ Keeping existing container.", :cyan
    end
  end
  say "๐Ÿ“‹ Final container status (docker compose ps):", :cyan
  docker_ps_output = ssh.exec!("cd #{docker_dir_remote} && docker compose ps --format json")
  if docker_ps_output.nil? || docker_ps_output.strip.empty? || docker_ps_output.include?("no configuration file")
    say "โš ๏ธ docker compose ps returned no valid output.", :yellow
  else
    begin
      services = JSON.parse(docker_ps_output)
      services = [services] if services.is_a?(Hash)
      postgres = services.find { |svc| svc["Service"] == "postgres" }
      status = postgres && postgres["State"]
      health = postgres && postgres["Health"]
      if (status == "running" && health == "healthy") || (health == "healthy")
        say "โœ… PostgreSQL container is running and healthy.", :green
      else
        say "โš ๏ธ PostgreSQL container is not healthy yet.", :yellow
      end
    rescue JSON::ParserError => e
      say "๐Ÿšจ Failed to parse docker compose ps output as JSON: #{e.message}", :red
    end
  end
  # 9. Check PostgreSQL readiness with retries
  say "๐Ÿ” Checking PostgreSQL health with retries...", :cyan
  max_attempts = 10
  attempt = 0
  success = false
  while attempt < max_attempts
    attempt += 1
    healthcheck = ssh.exec!("docker exec $(docker ps -qf name=postgres) pg_isready -U #{postgres_defaults[:postgres_user]} -d #{postgres_defaults[:postgres_db]} -h localhost")
    if healthcheck.include?("accepting connections")
      say "โœ… PostgreSQL is up and accepting connections! (attempt #{attempt})", :green
      success = true
      break
    else
      say "โณ PostgreSQL not ready yet, retrying in 5 seconds... (#{attempt + 1}/#{max_attempts})", :yellow
      sleep 5
    end
  end
  unless success
    say "โŒ PostgreSQL did not become ready after #{max_attempts} attempts.", :red
  end
  # 10. Allow PostgreSQL port through firewall (ufw)
  say "๐Ÿ›ก๏ธ Configuring firewall to allow PostgreSQL (port #{postgres_defaults[:postgres_port]})...", :cyan
  firewall = <<~EOH
    if command -v ufw >/dev/null; then
      if ! sudo ufw status | grep -q "#{postgres_defaults[:postgres_port]}"; then
        sudo ufw allow #{postgres_defaults[:postgres_port]}
      else
        echo "๐Ÿ’ก Port #{postgres_defaults[:postgres_port]} is already allowed in ufw."
      fi
    else
      echo "โš ๏ธ ufw not found. Skipping firewall configuration."
    fi
  EOH
  ssh.exec!(firewall)
end

def rollback

def rollback
  postgres_defaults = Kitsune::Kit::Defaults.postgres
  filled_options = Kitsune::Kit::OptionsBuilder.build(
    options,
    required: [:server_ip],
    defaults: Kitsune::Kit::Defaults.ssh
  )
  with_ssh_connection(filled_options) do |ssh|
    perform_rollback(ssh, postgres_defaults)
  end
end

def upload_file(ssh, content, remote_path)

def upload_file(ssh, content, remote_path)
  escaped_content = Shellwords.escape(content)
  ssh.exec!("mkdir -p #{File.dirname(remote_path)}")
  ssh.exec!("echo #{escaped_content} > #{remote_path}")
end

def with_ssh_connection(filled_options)

def with_ssh_connection(filled_options)
  server = filled_options[:server_ip]
  port   = filled_options[:ssh_port]
  key    = File.expand_path(filled_options[:ssh_key_path])
  say "๐Ÿ”‘ Connecting as deploy@#{server}:#{port}", :green
  Net::SSH.start(server, "deploy", port: port, keys: [key], non_interactive: true, timeout: 5) do |ssh|
    yield ssh
  end
end