create table if not exists users (
    id uuid primary key,
    email text not null unique,
    display_name_ciphertext bytea,
    display_name_nonce bytea,
    display_name_key_id text,
    password_hash text,
    is_active boolean not null default true,
    must_change_password boolean not null default false,
    initial_password_expires_at timestamptz,
    created_at timestamptz not null default now(),
    updated_at timestamptz not null default now(),
    last_login_at timestamptz,
    constraint users_email_lowercase check (email = lower(email)),
    constraint users_display_name_encryption_complete check (
        (
            display_name_ciphertext is null
            and display_name_nonce is null
            and display_name_key_id is null
        )
        or (
            display_name_ciphertext is not null
            and display_name_nonce is not null
            and display_name_key_id is not null
        )
    )
);

create table if not exists organizations (
    id uuid primary key,
    display_name_ciphertext bytea,
    display_name_nonce bytea,
    display_name_key_id text,
    schema_name text unique,
    status text not null default 'pending_approval',
    registration_email text not null,
    setup_completed_at timestamptz,
    approved_by_user_id uuid references users(id),
    approved_at timestamptz,
    rejected_by_user_id uuid references users(id),
    rejected_at timestamptz,
    rejection_reason text,
    created_at timestamptz not null default now(),
    updated_at timestamptz not null default now(),
    constraint organizations_status_valid check (
        status in ('pending_approval', 'approved', 'active', 'rejected', 'suspended')
    ),
    constraint organizations_registration_email_lowercase check (registration_email = lower(registration_email)),
    constraint organizations_schema_name_valid check (
        schema_name is null or schema_name ~ '^company_[a-z0-9_]+$'
    ),
    constraint organizations_display_name_encryption_complete check (
        (
            display_name_ciphertext is null
            and display_name_nonce is null
            and display_name_key_id is null
        )
        or (
            display_name_ciphertext is not null
            and display_name_nonce is not null
            and display_name_key_id is not null
        )
    )
);

create table if not exists user_organizations (
    user_id uuid not null references users(id) on delete cascade,
    organization_id uuid not null references organizations(id) on delete cascade,
    status text not null default 'pending_invitation',
    invited_by_user_id uuid references users(id),
    invited_at timestamptz,
    accepted_at timestamptz,
    created_at timestamptz not null default now(),
    updated_at timestamptz not null default now(),
    primary key (user_id, organization_id),
    constraint user_organizations_status_valid check (
        status in ('pending_invitation', 'active', 'disabled')
    )
);

create table if not exists organization_domains (
    id uuid primary key,
    organization_id uuid not null references organizations(id) on delete cascade,
    domain text not null unique,
    is_primary boolean not null default false,
    created_at timestamptz not null default now(),
    constraint organization_domains_domain_lowercase check (domain = lower(domain))
);

create index if not exists idx_user_organizations_organization_id
    on user_organizations (organization_id);

create index if not exists idx_organizations_status
    on organizations (status);
