defmodule Mv.Repo.Migrations.EnsureSystemActorUserExists do
  @moduledoc """
  Ensures the system actor user always exists.

  The system actor is used for systemic operations (email sync, cycle generation,
  background jobs). It is created by seeds in development; in production seeds
  may not run, so this migration guarantees the user exists.

  Creates a user with email "system@mila.local" (default from Mv.Helpers.SystemActor)
  and the Admin role. The user has no password and no OIDC ID, so it cannot log in.
  """
  use Ecto.Migration
  import Ecto.Query

  @system_user_email "system@mila.local"

  def up do
    admin_role_id = ensure_admin_role_exists()
    ensure_system_actor_user_exists(admin_role_id)
  end

  def down do
    # Not reversible - do not delete system user on rollback
    :ok
  end

  defp ensure_admin_role_exists do
    case repo().one(from(r in "roles", where: r.name == "Admin", select: r.id)) do
      nil ->
        execute("""
        INSERT INTO roles (id, name, description, permission_set_name, is_system_role, inserted_at, updated_at)
        VALUES (uuid_generate_v7(), 'Admin', 'Administrator with full access', 'admin', false, (now() AT TIME ZONE 'utc'), (now() AT TIME ZONE 'utc'))
        """)

        role_id = repo().one(from(r in "roles", where: r.name == "Admin", select: r.id))
        IO.puts("✅ Created 'Admin' role (was missing)")
        role_id

      role_id ->
        role_id
    end
  end

  defp ensure_system_actor_user_exists(_admin_role_id) do
    case repo().one(from(u in "users", where: u.email == ^@system_user_email, select: u.id)) do
      nil ->
        # Use subquery for role_id to avoid nil/empty-string UUID (CI can lag after role insert)
        execute("""
        INSERT INTO users (id, email, hashed_password, oidc_id, member_id, role_id)
        SELECT uuid_generate_v7(), '#{@system_user_email}', NULL, NULL, NULL, r.id
        FROM roles r
        WHERE r.name = 'Admin'
        LIMIT 1
        """)

        IO.puts("✅ Created system actor user (#{@system_user_email})")

      _ ->
        :ok
    end
  end
end
