create extension if not exists "pgcrypto";

create table if not exists app_users (
  id uuid primary key default gen_random_uuid(),
  username varchar(100) unique not null,
  password_hash text not null,
  is_active boolean not null default true,
  created_at timestamptz not null default now()
);

create table if not exists roles (
  id uuid primary key default gen_random_uuid(),
  code varchar(100) unique not null,
  name varchar(120) not null,
  description text,
  created_at timestamptz not null default now()
);

create table if not exists permissions (
  id uuid primary key default gen_random_uuid(),
  resource varchar(100) not null,
  action varchar(50) not null,
  unique(resource, action)
);

create table if not exists user_roles (
  user_id uuid not null references app_users(id) on delete cascade,
  role_id uuid not null references roles(id) on delete cascade,
  primary key(user_id, role_id)
);

create table if not exists table_groups (
  id uuid primary key default gen_random_uuid(),
  code varchar(100) unique not null,
  name varchar(120) not null,
  description text
);

create table if not exists table_group_tables (
  id uuid primary key default gen_random_uuid(),
  table_group_id uuid not null references table_groups(id) on delete cascade,
  table_name varchar(120) unique not null
);

create table if not exists role_permissions (
  role_id uuid not null references roles(id) on delete cascade,
  permission_id uuid not null references permissions(id) on delete cascade,
  table_group_id uuid references table_groups(id) on delete cascade,
  primary key(role_id, permission_id, table_group_id)
);

create table if not exists audit_logs (
  id bigserial primary key,
  user_id uuid references app_users(id) on delete set null,
  action varchar(100) not null,
  resource_type varchar(100) not null,
  resource_name varchar(150),
  sql_text text,
  details jsonb not null default '{}'::jsonb,
  success boolean not null default true,
  created_at timestamptz not null default now()
);

create table if not exists finance_entries (
  id bigserial primary key,
  title varchar(120) not null,
  amount numeric(12, 2) not null,
  currency varchar(10) not null default 'USD',
  created_at timestamptz not null default now()
);

create table if not exists user_profiles (
  id bigserial primary key,
  email varchar(190) not null unique,
  full_name varchar(190) not null,
  status varchar(50) not null default 'active',
  created_at timestamptz not null default now()
);

create table if not exists app_logs (
  id bigserial primary key,
  level varchar(20) not null,
  message text not null,
  created_at timestamptz not null default now()
);

insert into table_groups (code, name, description)
values
  ('finance', 'Finance', 'Financial tables'),
  ('users', 'Users', 'User domain tables'),
  ('logs', 'Logs', 'Log and audit related tables')
on conflict (code) do nothing;

insert into table_group_tables (table_group_id, table_name)
select tg.id, mapping.table_name
from table_groups tg
join (
  values
    ('finance', 'finance_entries'),
    ('users', 'user_profiles'),
    ('logs', 'app_logs')
) as mapping(group_code, table_name)
  on mapping.group_code = tg.code
on conflict (table_name) do nothing;

insert into permissions (resource, action)
values
  ('global', 'read'),
  ('global', 'write'),
  ('global', 'delete'),
  ('global', 'schema'),
  ('global', 'execute')
on conflict (resource, action) do nothing;

insert into roles (code, name, description)
values
  ('root', 'Root', 'Full access'),
  ('group_admin', 'Group Admin', 'Admin of assigned table groups'),
  ('editor', 'Editor', 'Read and write access'),
  ('viewer', 'Viewer', 'Read-only access')
on conflict (code) do nothing;

insert into app_users (username, password_hash)
values
  ('root', crypt('ChangeMe123!', gen_salt('bf')))
on conflict (username) do nothing;

insert into user_roles (user_id, role_id)
select u.id, r.id
from app_users u
join roles r on r.code = 'root'
where u.username = 'root'
on conflict do nothing;

insert into role_permissions (role_id, permission_id, table_group_id)
select r.id, p.id, null
from roles r
join permissions p on p.resource = 'global'
where r.code = 'root'
on conflict do nothing;

insert into finance_entries (title, amount, currency)
values
  ('Subscription revenue', 1500.00, 'USD'),
  ('Cloud hosting', -420.00, 'USD');

insert into user_profiles (email, full_name, status)
values
  ('root@example.com', 'Root Administrator', 'active'),
  ('analyst@example.com', 'Finance Analyst', 'active')
on conflict (email) do nothing;

insert into app_logs (level, message)
values
  ('info', 'System initialized'),
  ('warn', 'Background job delayed');
