CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE EXTENSION IF NOT EXISTS citext;

CREATE TABLE IF NOT EXISTS users (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  email citext NOT NULL UNIQUE,
  password_hash text NOT NULL,
  display_name text,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  disabled_at timestamptz,
  CONSTRAINT users_email_not_blank CHECK (length(trim(email::text)) > 0),
  CONSTRAINT users_password_hash_not_blank CHECK (length(trim(password_hash)) > 0)
);

CREATE TABLE IF NOT EXISTS auth_sessions (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  token_hash text NOT NULL UNIQUE,
  issued_at timestamptz NOT NULL DEFAULT now(),
  expires_at timestamptz NOT NULL,
  revoked_at timestamptz,
  user_agent text,
  device_label text,
  CONSTRAINT auth_sessions_token_hash_not_blank CHECK (length(trim(token_hash)) > 0),
  CONSTRAINT auth_sessions_expires_after_issued CHECK (expires_at > issued_at)
);

CREATE TABLE IF NOT EXISTS synced_resources (
  server_id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  owner_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  resource_type text NOT NULL,
  client_id text NOT NULL,
  payload_json jsonb NOT NULL,
  schema_version integer NOT NULL,
  client_updated_at timestamptz NOT NULL,
  server_updated_at timestamptz NOT NULL DEFAULT now(),
  deleted_at timestamptz,
  origin_device_id text,
  CONSTRAINT synced_resources_type_check CHECK (
    resource_type IN (
      'exercise',
      'program',
      'workoutTemplate',
      'workoutHistory',
      'mediaAsset'
    )
  ),
  CONSTRAINT synced_resources_client_id_not_blank CHECK (length(trim(client_id)) > 0),
  CONSTRAINT synced_resources_schema_version_positive CHECK (schema_version > 0),
  CONSTRAINT synced_resources_owner_type_client_unique UNIQUE (
    owner_user_id,
    resource_type,
    client_id
  )
);

CREATE INDEX IF NOT EXISTS idx_synced_resources_owner_type_updated
  ON synced_resources (owner_user_id, resource_type, server_updated_at);

CREATE INDEX IF NOT EXISTS idx_synced_resources_owner_updated
  ON synced_resources (owner_user_id, server_updated_at);

CREATE OR REPLACE FUNCTION set_synced_resources_server_updated_at()
RETURNS trigger AS $$
BEGIN
  NEW.server_updated_at = now();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS trg_synced_resources_set_server_updated_at
  ON synced_resources;

CREATE TRIGGER trg_synced_resources_set_server_updated_at
  BEFORE UPDATE ON synced_resources
  FOR EACH ROW
  EXECUTE FUNCTION set_synced_resources_server_updated_at();

CREATE TABLE IF NOT EXISTS shares (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  sender_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  resource_type text NOT NULL,
  payload_json jsonb NOT NULL,
  created_at timestamptz NOT NULL DEFAULT now(),
  revoked_at timestamptz,
  CONSTRAINT shares_resource_type_check CHECK (
    resource_type IN ('program', 'workoutTemplate')
  )
);

CREATE TABLE IF NOT EXISTS share_recipients (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  share_id uuid NOT NULL REFERENCES shares(id) ON DELETE CASCADE,
  recipient_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  status text NOT NULL DEFAULT 'pending',
  responded_at timestamptz,
  CONSTRAINT share_recipients_status_check CHECK (
    status IN ('pending', 'accepted', 'declined', 'revoked')
  ),
  CONSTRAINT share_recipients_share_user_unique UNIQUE (
    share_id,
    recipient_user_id
  )
);

CREATE INDEX IF NOT EXISTS idx_auth_sessions_user_id
  ON auth_sessions (user_id);

CREATE INDEX IF NOT EXISTS idx_shares_sender_user_id
  ON shares (sender_user_id);

CREATE INDEX IF NOT EXISTS idx_share_recipients_recipient_status
  ON share_recipients (recipient_user_id, status);
