use strict;
use warnings;

use Test::More;
use File::Temp qw(tempdir);
use DBIO::Util ();

my ($dsn, $user, $pass) = @ENV{map { "DBIO_TEST_PG_${_}" } qw(DSN USER PASS)};

plan skip_all => 'Set DBIO_TEST_PG_DSN, _USER and _PASS to run this test'
  unless $dsn && $user;

require DBI;

my $dbh = DBI->connect($dsn, $user, $pass, {
  AutoCommit => 1,
  RaiseError => 1,
  PrintError => 0,
});

my $schema_name = 'dbio_generate_live';

END {
  return unless $dbh;
  eval { $dbh->do("DROP SCHEMA IF EXISTS $schema_name CASCADE") };
}

$dbh->do("DROP SCHEMA IF EXISTS $schema_name CASCADE");
$dbh->do("CREATE SCHEMA $schema_name");
$dbh->do("CREATE TYPE $schema_name.role_type AS ENUM ('admin', 'user')");
$dbh->do(qq{
  CREATE TABLE $schema_name.users (
    id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    email text NOT NULL,
    role $schema_name.role_type NOT NULL DEFAULT 'user'
  )
});
$dbh->do(qq{
  CREATE TABLE $schema_name.posts (
    id    integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    owner integer NOT NULL REFERENCES $schema_name.users(id) ON DELETE CASCADE,
    title text    NOT NULL
  )
});
$dbh->do(qq{
  CREATE TABLE $schema_name.tree (
    id     integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    parent integer REFERENCES $schema_name.tree(id),
    label  text NOT NULL
  )
});
$dbh->do(qq{
  CREATE UNIQUE INDEX users_lower_email_idx
    ON $schema_name.users (lower(email))
});
$dbh->do(qq{
  CREATE INDEX users_role_partial_idx
    ON $schema_name.users (role)
    WHERE role <> 'user'
});
$dbh->do(qq{
  ALTER TABLE $schema_name.users ENABLE ROW LEVEL SECURITY
});
$dbh->do(qq{
  CREATE POLICY users_self
    ON $schema_name.users
    USING (id > 0)
});

my $tmpdir = File::Temp::tempdir(CLEANUP => 1);

# Use DBIO::Generate + DBIO::PostgreSQL::Introspect directly (the new path)
require DBIO::Generate;
require DBIO::PostgreSQL::Introspect;

# Keep using $dbh: the END block above must still be connected to drop the
# test schema, otherwise leftovers pollute later tests on the same database.
my $intro = DBIO::PostgreSQL::Introspect->new(
  dbh => $dbh,
  schema_filter => [$schema_name],
  preserve_case => 0,
);

my $gen = DBIO::Generate->new(
  dump_directory => $tmpdir,
  schema_class   => 'TestGen::Schema',
  style          => 'vanilla',
  use_namespaces => 1,
  quiet          => 1,
);

$gen->dump($intro);

# --- Verify generated files ---
ok(-e "$tmpdir/TestGen/Schema/Result/User.pm", 'User.pm generated');
ok(-e "$tmpdir/TestGen/Schema/Result/Post.pm", 'Post.pm generated');
ok(-e "$tmpdir/TestGen/Schema/Result/Tree.pm", 'Tree.pm generated');

my $user_src = DBIO::Util::slurp_file_utf8("$tmpdir/TestGen/Schema/Result/User.pm");
# DBIO::Generate emits string literals via B::perlstring, i.e. double-quoted
# (->table("users")), so accept either quote style — same tolerance as the
# offline sibling t/25-generate-via-introspect.t.
like($user_src, qr/__PACKAGE__->table\(['"]users['"]\)/, 'User table name set');
like($user_src, qr/__PACKAGE__->set_primary_key\(['"]id['"]\)/, 'User primary key set');
like($user_src, qr/__PACKAGE__->pg_schema\(['"]\Q$schema_name\E['"]\)/, 'User schema qualifier emitted');

# --- Index metadata (pg_index via result_class_extra_statements) ---
ok($user_src =~ /pg_index/m, 'pg_index metadata present in User');

# --- RLS via pg_rls ---
ok($user_src =~ /pg_rls/m, 'pg_rls statement present for RLS-enabled table');

# --- Foreign key → belongs_to ---
my $post_src = DBIO::Util::slurp_file_utf8("$tmpdir/TestGen/Schema/Result/Post.pm");
like($post_src, qr/belongs_to/, 'Post has belongs_to relationship');

# --- has_many on inverse side ---
like($user_src, qr/has_many/, 'User has has_many relationship for posts');

# --- Self-referential FK ---
my $tree_src = DBIO::Util::slurp_file_utf8("$tmpdir/TestGen/Schema/Result/Tree.pm");
like($tree_src, qr/belongs_to/, 'Tree has relationship for self-referential FK');

# --- Enum type preserved ---
like($user_src, qr/enum/, 'enum type in role column metadata');

done_testing;
