import { db, type DatabaseClient } from './client.js';

export const ensureSchema = async (database: DatabaseClient = db) => {
  await database.query(`
    CREATE EXTENSION IF NOT EXISTS pgcrypto;

    CREATE TABLE IF NOT EXISTS users (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      email VARCHAR(255) NOT NULL UNIQUE,
      password_hash VARCHAR(255),
      name VARCHAR(160) NOT NULL,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    CREATE TABLE IF NOT EXISTS workspaces (
      id INTEGER PRIMARY KEY,
      name VARCHAR(160) NOT NULL DEFAULT 'My Flock',
      workspace_type VARCHAR(16) NOT NULL DEFAULT 'standard',
      billing_email VARCHAR(255),
      billing_plan VARCHAR(32) NOT NULL DEFAULT 'household_basic',
      billing_interval VARCHAR(16) NOT NULL DEFAULT 'monthly',
      subscription_status VARCHAR(32) NOT NULL DEFAULT 'none',
      stripe_customer_id VARCHAR(255),
      stripe_subscription_id VARCHAR(255),
      rescue_verification_status VARCHAR(32) NOT NULL DEFAULT 'not_required',
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
      updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    ALTER TABLE workspaces
      DROP CONSTRAINT IF EXISTS workspaces_id_check;

    ALTER TABLE users
      ADD COLUMN IF NOT EXISTS education_opt_out BOOLEAN NOT NULL DEFAULT FALSE;

    ALTER TABLE workspaces
      ADD COLUMN IF NOT EXISTS billing_email VARCHAR(255),
      ADD COLUMN IF NOT EXISTS billing_plan VARCHAR(32) NOT NULL DEFAULT 'household_basic',
      ADD COLUMN IF NOT EXISTS billing_interval VARCHAR(16) NOT NULL DEFAULT 'monthly',
      ADD COLUMN IF NOT EXISTS subscription_status VARCHAR(32) NOT NULL DEFAULT 'none',
      ADD COLUMN IF NOT EXISTS stripe_customer_id VARCHAR(255),
      ADD COLUMN IF NOT EXISTS stripe_subscription_id VARCHAR(255),
      ADD COLUMN IF NOT EXISTS rescue_verification_status VARCHAR(32) NOT NULL DEFAULT 'not_required';

    CREATE UNIQUE INDEX IF NOT EXISTS idx_workspaces_stripe_subscription_id
      ON workspaces (stripe_subscription_id)
      WHERE stripe_subscription_id IS NOT NULL;

    CREATE INDEX IF NOT EXISTS idx_workspaces_stripe_customer_id
      ON workspaces (stripe_customer_id)
      WHERE stripe_customer_id IS NOT NULL;

    CREATE INDEX IF NOT EXISTS idx_workspaces_rescue_status
      ON workspaces (workspace_type, rescue_verification_status, created_at DESC);

    UPDATE workspaces
    SET subscription_status = 'none'
    WHERE workspace_type = 'standard'
      AND stripe_subscription_id IS NULL
      AND subscription_status = 'active';

    UPDATE workspaces
    SET rescue_verification_status = 'pending'
    WHERE workspace_type = 'rescue'
      AND rescue_verification_status = 'not_required';

    CREATE TABLE IF NOT EXISTS workspace_members (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
      user_id UUID REFERENCES users(id) ON DELETE CASCADE,
      invite_email VARCHAR(255) NOT NULL,
      name VARCHAR(160) NOT NULL,
      role VARCHAR(16) NOT NULL DEFAULT 'caregiver',
      accepted_at TIMESTAMPTZ,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    ALTER TABLE workspace_members
      ADD COLUMN IF NOT EXISTS email VARCHAR(255),
      ADD COLUMN IF NOT EXISTS user_id UUID REFERENCES users(id) ON DELETE CASCADE,
      ADD COLUMN IF NOT EXISTS invite_email VARCHAR(255),
      ADD COLUMN IF NOT EXISTS accepted_at TIMESTAMPTZ;

    UPDATE workspace_members
    SET role = CASE
      WHEN role = 'manager' THEN 'assistant'
      WHEN role = 'staff' THEN 'caregiver'
      ELSE role
    END
    WHERE role IN ('manager', 'staff');

    DO $$
    BEGIN
      IF EXISTS (
        SELECT 1
        FROM information_schema.columns
        WHERE table_name = 'workspace_members'
          AND column_name = 'email'
      ) THEN
        UPDATE workspace_members
        SET invite_email = COALESCE(invite_email, email)
        WHERE invite_email IS NULL;
      END IF;
    END $$;

    UPDATE workspace_members
    SET invite_email = ''
    WHERE invite_email IS NULL;

    UPDATE workspace_members
    SET email = invite_email
    WHERE email IS NULL;

    ALTER TABLE workspace_members
      ALTER COLUMN invite_email SET NOT NULL;

    CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_members_workspace_email
      ON workspace_members (workspace_id, invite_email);

    CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_members_workspace_user
      ON workspace_members (workspace_id, user_id)
      WHERE user_id IS NOT NULL;

    CREATE INDEX IF NOT EXISTS idx_workspace_members_user_accepted
      ON workspace_members (user_id, accepted_at, workspace_id)
      WHERE user_id IS NOT NULL;

    CREATE INDEX IF NOT EXISTS idx_workspace_members_owner_email
      ON workspace_members (LOWER(COALESCE(invite_email, email)), workspace_id)
      WHERE role = 'owner'
        AND accepted_at IS NOT NULL;

    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,
      active_workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
      token_hash VARCHAR(255) NOT NULL UNIQUE,
      expires_at TIMESTAMPTZ NOT NULL,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    CREATE INDEX IF NOT EXISTS idx_auth_sessions_created_user
      ON auth_sessions (created_at DESC, user_id);

    CREATE TABLE IF NOT EXISTS daily_education (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      publish_date DATE NOT NULL UNIQUE,
      fact TEXT NOT NULL,
      quiz_questions JSONB NOT NULL DEFAULT '[]'::jsonb,
      created_by_user_id UUID REFERENCES users(id) ON DELETE SET NULL,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
      updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    ALTER TABLE daily_education
      ALTER COLUMN quiz_questions SET DEFAULT '[]'::jsonb;

    CREATE INDEX IF NOT EXISTS idx_daily_education_publish_date
      ON daily_education (publish_date DESC);

    CREATE TABLE IF NOT EXISTS education_question_bank (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      prompt VARCHAR(500) NOT NULL,
      options JSONB NOT NULL,
      correct_answer_index INTEGER NOT NULL,
      explanation VARCHAR(800),
      created_by_user_id UUID REFERENCES users(id) ON DELETE SET NULL,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
      updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
      CHECK (correct_answer_index >= 0 AND correct_answer_index <= 3)
    );

    CREATE INDEX IF NOT EXISTS idx_education_question_bank_created
      ON education_question_bank (created_at DESC);

    CREATE TABLE IF NOT EXISTS integration_tokens (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
      workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
      name VARCHAR(160) NOT NULL,
      token_hash VARCHAR(255) NOT NULL UNIQUE,
      token_prefix VARCHAR(32) NOT NULL,
      scope VARCHAR(16) NOT NULL DEFAULT 'read_write',
      last_used_at TIMESTAMPTZ,
      expires_at TIMESTAMPTZ,
      revoked_at TIMESTAMPTZ,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    ALTER TABLE integration_tokens
      ADD COLUMN IF NOT EXISTS workspace_id INTEGER REFERENCES workspaces(id) ON DELETE CASCADE,
      ADD COLUMN IF NOT EXISTS name VARCHAR(160) NOT NULL DEFAULT 'Integration token',
      ADD COLUMN IF NOT EXISTS token_prefix VARCHAR(32),
      ADD COLUMN IF NOT EXISTS scope VARCHAR(16) NOT NULL DEFAULT 'read_write',
      ADD COLUMN IF NOT EXISTS last_used_at TIMESTAMPTZ,
      ADD COLUMN IF NOT EXISTS expires_at TIMESTAMPTZ,
      ADD COLUMN IF NOT EXISTS revoked_at TIMESTAMPTZ;

    UPDATE integration_tokens
    SET token_prefix = LEFT(token_hash, 12)
    WHERE token_prefix IS NULL;

    CREATE INDEX IF NOT EXISTS idx_integration_tokens_user_workspace
      ON integration_tokens (user_id, workspace_id, created_at DESC);

    CREATE INDEX IF NOT EXISTS idx_integration_tokens_lookup
      ON integration_tokens (token_hash)
      WHERE revoked_at IS NULL;

    CREATE TABLE IF NOT EXISTS auth_accounts (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
      provider_key VARCHAR(32) NOT NULL,
      provider_subject VARCHAR(255) NOT NULL,
      provider_email VARCHAR(255),
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    CREATE UNIQUE INDEX IF NOT EXISTS idx_auth_accounts_provider_subject
      ON auth_accounts (provider_key, provider_subject);

    CREATE TABLE IF NOT EXISTS oauth_states (
      id UUID PRIMARY KEY,
      provider_key VARCHAR(32) NOT NULL,
      code_verifier VARCHAR(255) NOT NULL,
      redirect_to TEXT NOT NULL,
      expires_at TIMESTAMPTZ NOT NULL
    );

    CREATE TABLE IF NOT EXISTS magic_link_tokens (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      email VARCHAR(255) NOT NULL,
      name VARCHAR(160),
      token_hash VARCHAR(255) NOT NULL UNIQUE,
      redirect_to TEXT NOT NULL,
      expires_at TIMESTAMPTZ NOT NULL,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    CREATE INDEX IF NOT EXISTS idx_magic_link_tokens_email
      ON magic_link_tokens (email, created_at DESC);

    CREATE TABLE IF NOT EXISTS birds (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      workspace_id INTEGER NOT NULL DEFAULT 1,
      name VARCHAR(120) NOT NULL,
      tag_id VARCHAR(80),
      species VARCHAR(120) NOT NULL,
      motivators VARCHAR(1000),
      demotivators VARCHAR(1000),
      favorite_snack VARCHAR(160),
      vet_clinic_name VARCHAR(160),
      vet_clinic_address VARCHAR(500),
      vet_account_number VARCHAR(120),
      vet_doctor_name VARCHAR(160),
      gender VARCHAR(16) NOT NULL DEFAULT 'unknown',
      date_of_birth DATE,
      gotcha_day DATE,
      chart_color VARCHAR(7) NOT NULL DEFAULT '#cb3a35',
      photo_data_url TEXT,
      photo_object_key TEXT,
      photo_content_type VARCHAR(80),
      photo_updated_at TIMESTAMPTZ,
      notify_on_dob BOOLEAN NOT NULL DEFAULT FALSE,
      notify_on_gotcha_day BOOLEAN NOT NULL DEFAULT FALSE,
      public_profile_code VARCHAR(32),
      public_profile_enabled BOOLEAN NOT NULL DEFAULT FALSE,
      memorialized_at TIMESTAMPTZ,
      memorialized_on DATE,
      memorial_note VARCHAR(1000),
      notify_on_memorial_day BOOLEAN NOT NULL DEFAULT FALSE,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    ALTER TABLE birds
      ADD COLUMN IF NOT EXISTS workspace_id INTEGER NOT NULL DEFAULT 1,
      ADD COLUMN IF NOT EXISTS motivators VARCHAR(1000),
      ADD COLUMN IF NOT EXISTS demotivators VARCHAR(1000),
      ADD COLUMN IF NOT EXISTS favorite_snack VARCHAR(160),
      ADD COLUMN IF NOT EXISTS vet_clinic_name VARCHAR(160),
      ADD COLUMN IF NOT EXISTS vet_clinic_address VARCHAR(500),
      ADD COLUMN IF NOT EXISTS vet_account_number VARCHAR(120),
      ADD COLUMN IF NOT EXISTS vet_doctor_name VARCHAR(160),
      ADD COLUMN IF NOT EXISTS gender VARCHAR(16) NOT NULL DEFAULT 'unknown',
      ADD COLUMN IF NOT EXISTS date_of_birth DATE,
      ADD COLUMN IF NOT EXISTS gotcha_day DATE,
      ADD COLUMN IF NOT EXISTS chart_color VARCHAR(7) NOT NULL DEFAULT '#cb3a35',
      ADD COLUMN IF NOT EXISTS photo_data_url TEXT,
      ADD COLUMN IF NOT EXISTS photo_object_key TEXT,
      ADD COLUMN IF NOT EXISTS photo_content_type VARCHAR(80),
      ADD COLUMN IF NOT EXISTS photo_updated_at TIMESTAMPTZ,
      ADD COLUMN IF NOT EXISTS notify_on_dob BOOLEAN NOT NULL DEFAULT FALSE,
      ADD COLUMN IF NOT EXISTS notify_on_gotcha_day BOOLEAN NOT NULL DEFAULT FALSE,
      ADD COLUMN IF NOT EXISTS public_profile_code VARCHAR(32),
      ADD COLUMN IF NOT EXISTS public_profile_enabled BOOLEAN NOT NULL DEFAULT FALSE,
      ADD COLUMN IF NOT EXISTS memorialized_at TIMESTAMPTZ,
      ADD COLUMN IF NOT EXISTS memorialized_on DATE,
      ADD COLUMN IF NOT EXISTS memorial_note VARCHAR(1000),
      ADD COLUMN IF NOT EXISTS notify_on_memorial_day BOOLEAN NOT NULL DEFAULT FALSE;

    ALTER TABLE birds
      ALTER COLUMN tag_id DROP NOT NULL;

    UPDATE birds
    SET tag_id = NULL
    WHERE tag_id IS NOT NULL
      AND LOWER(BTRIM(tag_id)) IN ('unknown', 'not recorded', 'n/a', 'na', 'none');

    DO $$
    BEGIN
      IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'birds_workspace_fk') THEN
        ALTER TABLE birds
          ADD CONSTRAINT birds_workspace_fk
          FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE;
      END IF;
    END $$;

    DELETE FROM workspaces
    WHERE id = 1
      AND name = 'My Flock'
      AND NOT EXISTS (SELECT 1 FROM workspace_members WHERE workspace_members.workspace_id = workspaces.id)
      AND NOT EXISTS (SELECT 1 FROM birds WHERE birds.workspace_id = workspaces.id);

    ALTER TABLE birds
      DROP CONSTRAINT IF EXISTS birds_tag_id_key;

    DROP INDEX IF EXISTS idx_birds_workspace_tag_id;

    CREATE UNIQUE INDEX IF NOT EXISTS idx_birds_global_tag_id
      ON birds (LOWER(BTRIM(tag_id)))
      WHERE tag_id IS NOT NULL
        AND BTRIM(tag_id) <> ''
        AND LOWER(BTRIM(tag_id)) NOT IN ('unknown', 'not recorded', 'n/a', 'na', 'none');

    CREATE INDEX IF NOT EXISTS idx_birds_workspace_active_name
      ON birds (workspace_id, name)
      WHERE memorialized_at IS NULL;

    CREATE INDEX IF NOT EXISTS idx_birds_workspace_memorialized
      ON birds (workspace_id, memorialized_on DESC, name)
      WHERE memorialized_at IS NOT NULL;

    CREATE INDEX IF NOT EXISTS idx_birds_tag_lookup_active
      ON birds (LOWER(tag_id), created_at)
      WHERE tag_id IS NOT NULL
        AND BTRIM(tag_id) <> ''
        AND LOWER(BTRIM(tag_id)) NOT IN ('unknown', 'not recorded', 'n/a', 'na', 'none')
        AND memorialized_at IS NULL;

    CREATE INDEX IF NOT EXISTS idx_birds_photo_object_key
      ON birds (photo_object_key)
      WHERE photo_object_key IS NOT NULL;

    CREATE UNIQUE INDEX IF NOT EXISTS idx_birds_public_profile_code
      ON birds (public_profile_code)
      WHERE public_profile_code IS NOT NULL;

	    CREATE TABLE IF NOT EXISTS pending_bird_transfers (
	      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      bird_id UUID NOT NULL REFERENCES birds(id) ON DELETE CASCADE,
      source_workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
      destination_owner_email VARCHAR(255) NOT NULL,
      requested_by_user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
      completed_at TIMESTAMPTZ,
      completed_workspace_id INTEGER REFERENCES workspaces(id) ON DELETE SET NULL,
      last_error TEXT,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    ALTER TABLE pending_bird_transfers
      ADD COLUMN IF NOT EXISTS completed_at TIMESTAMPTZ,
      ADD COLUMN IF NOT EXISTS completed_workspace_id INTEGER REFERENCES workspaces(id) ON DELETE SET NULL,
      ADD COLUMN IF NOT EXISTS last_error TEXT;

    CREATE INDEX IF NOT EXISTS idx_pending_bird_transfers_destination_email
      ON pending_bird_transfers (LOWER(destination_owner_email), created_at DESC)
      WHERE completed_at IS NULL;

	    CREATE UNIQUE INDEX IF NOT EXISTS idx_pending_bird_transfers_open_bird
	      ON pending_bird_transfers (bird_id)
	      WHERE completed_at IS NULL;

    CREATE TABLE IF NOT EXISTS bird_transfer_codes (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      code VARCHAR(32) NOT NULL UNIQUE,
      bird_id UUID NOT NULL REFERENCES birds(id) ON DELETE CASCADE,
      source_workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
      requested_by_user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
      completed_at TIMESTAMPTZ,
      completed_workspace_id INTEGER REFERENCES workspaces(id) ON DELETE SET NULL,
      revoked_at TIMESTAMPTZ,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    CREATE INDEX IF NOT EXISTS idx_bird_transfer_codes_open_bird
      ON bird_transfer_codes (bird_id, created_at DESC)
      WHERE completed_at IS NULL
        AND revoked_at IS NULL;

    CREATE INDEX IF NOT EXISTS idx_bird_transfer_codes_code_open
      ON bird_transfer_codes (code)
      WHERE completed_at IS NULL
        AND revoked_at IS NULL;

	    CREATE TABLE IF NOT EXISTS flock_notes (
	      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
	      workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
	      bird_id UUID REFERENCES birds(id) ON DELETE SET NULL,
	      title VARCHAR(160) NOT NULL,
	      body TEXT NOT NULL,
	      created_by_user_id UUID REFERENCES users(id) ON DELETE SET NULL,
	      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
	      updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
	    );

	    CREATE INDEX IF NOT EXISTS idx_flock_notes_workspace_updated
	      ON flock_notes (workspace_id, updated_at DESC);

	    CREATE INDEX IF NOT EXISTS idx_flock_notes_bird_updated
	      ON flock_notes (bird_id, updated_at DESC)
	      WHERE bird_id IS NOT NULL;

	    CREATE TABLE IF NOT EXISTS audit_log_entries (
	      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
	      workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
	      user_id UUID REFERENCES users(id) ON DELETE SET NULL,
	      actor_name VARCHAR(160),
	      actor_email VARCHAR(255),
	      action VARCHAR(80) NOT NULL,
	      entity_type VARCHAR(80) NOT NULL,
	      entity_id VARCHAR(120),
	      entity_name VARCHAR(255),
	      details JSONB NOT NULL DEFAULT '{}'::jsonb,
	      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
	    );

	    CREATE INDEX IF NOT EXISTS idx_audit_log_entries_workspace_created
	      ON audit_log_entries (workspace_id, created_at DESC);

	    CREATE INDEX IF NOT EXISTS idx_audit_log_entries_entity
	      ON audit_log_entries (workspace_id, entity_type, entity_id, created_at DESC);

	    CREATE TABLE IF NOT EXISTS weight_records (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      bird_id UUID NOT NULL REFERENCES birds(id) ON DELETE CASCADE,
      weight_grams NUMERIC(8, 2) NOT NULL CHECK (weight_grams > 0),
      recorded_on DATE NOT NULL,
      notes VARCHAR(280),
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
      UNIQUE (bird_id, recorded_on)
    );

    CREATE TABLE IF NOT EXISTS vet_visits (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      bird_id UUID NOT NULL REFERENCES birds(id) ON DELETE CASCADE,
      visited_on DATE NOT NULL,
      clinic_name VARCHAR(160) NOT NULL,
      reason VARCHAR(160) NOT NULL,
      notes VARCHAR(1000),
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    CREATE TABLE IF NOT EXISTS medications (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      bird_id UUID NOT NULL REFERENCES birds(id) ON DELETE CASCADE,
      name VARCHAR(160) NOT NULL,
      dosage VARCHAR(160) NOT NULL,
      frequency VARCHAR(160) NOT NULL,
      dose_schedule JSONB NOT NULL DEFAULT '[{"key":"dose-1","label":"Dose","time":""}]'::jsonb,
      route VARCHAR(80),
      start_date DATE NOT NULL,
      end_date DATE,
      notes VARCHAR(1000),
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
      CHECK (end_date IS NULL OR end_date >= start_date)
    );

    ALTER TABLE medications
      ADD COLUMN IF NOT EXISTS dose_schedule JSONB NOT NULL DEFAULT '[{"key":"dose-1","label":"Dose","time":""}]'::jsonb;

    CREATE TABLE IF NOT EXISTS bird_milestone_reminder_deliveries (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      bird_id UUID NOT NULL REFERENCES birds(id) ON DELETE CASCADE,
      workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
      reminder_type VARCHAR(24) NOT NULL CHECK (reminder_type IN ('hatch_day', 'gotcha_day', 'memorial_day')),
      reminder_year INTEGER NOT NULL,
      delivered_on DATE NOT NULL,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
      UNIQUE (bird_id, reminder_type, reminder_year)
    );

    ALTER TABLE bird_milestone_reminder_deliveries
      DROP CONSTRAINT IF EXISTS bird_milestone_reminder_deliveries_reminder_type_check;

    ALTER TABLE bird_milestone_reminder_deliveries
      ADD CONSTRAINT bird_milestone_reminder_deliveries_reminder_type_check
      CHECK (reminder_type IN ('hatch_day', 'gotcha_day', 'memorial_day'));

    CREATE TABLE IF NOT EXISTS medication_administrations (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      medication_id UUID NOT NULL REFERENCES medications(id) ON DELETE CASCADE,
      bird_id UUID NOT NULL REFERENCES birds(id) ON DELETE CASCADE,
      administered_on DATE NOT NULL,
      administration_slot VARCHAR(80) NOT NULL DEFAULT 'dose-1',
      status VARCHAR(20) NOT NULL CHECK (status IN ('administered', 'missed')),
      notes VARCHAR(500),
      created_by_user_id UUID REFERENCES users(id) ON DELETE SET NULL,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
    );

    ALTER TABLE medication_administrations
      ADD COLUMN IF NOT EXISTS administration_slot VARCHAR(80) NOT NULL DEFAULT 'dose-1';

    ALTER TABLE medication_administrations
      DROP CONSTRAINT IF EXISTS medication_administrations_medication_id_administered_on_key;

    CREATE UNIQUE INDEX IF NOT EXISTS idx_medication_administrations_unique_slot
      ON medication_administrations (medication_id, administered_on, administration_slot);

    CREATE INDEX IF NOT EXISTS idx_weight_records_bird_recorded_on
      ON weight_records (bird_id, recorded_on DESC);

    CREATE INDEX IF NOT EXISTS idx_vet_visits_bird_visited_on
      ON vet_visits (bird_id, visited_on DESC);

    CREATE INDEX IF NOT EXISTS idx_medications_bird_start_date
      ON medications (bird_id, start_date DESC);

    CREATE INDEX IF NOT EXISTS idx_bird_milestone_reminder_deliveries_workspace
      ON bird_milestone_reminder_deliveries (workspace_id, delivered_on DESC);

    CREATE INDEX IF NOT EXISTS idx_medication_administrations_bird_administered_on
      ON medication_administrations (bird_id, administered_on DESC);

    CREATE INDEX IF NOT EXISTS idx_medication_administrations_medication_date
      ON medication_administrations (medication_id, administered_on DESC, created_at DESC);

    DO $$
    BEGIN
      IF EXISTS (
        SELECT 1
        FROM information_schema.columns
        WHERE table_name = 'birds'
          AND column_name = 'is_female'
      ) THEN
        UPDATE birds
        SET gender = CASE
          WHEN is_female IS TRUE THEN 'female'
          WHEN is_female IS FALSE THEN 'male'
          ELSE gender
        END
        WHERE gender = 'unknown';
      END IF;
    END $$;
  `);
};
