import { db } from '../db/client.js';
import type {
  BirdGender,
  BirdMilestoneReminderCandidateRow,
  BirdMilestoneReminderDeliveryRow,
  BirdMilestoneReminderType,
  BirdRow,
  BirdTransferCodeRow,
  LostBirdMatchRow,
  MedicationAdministrationRow,
  MedicationDoseScheduleItem,
  MedicationRow,
  PendingBirdTransferRow,
  VetVisitRow,
  WeightRow,
} from '../types.js';

const birdSelectFields = `
  birds.id,
  birds.workspace_id,
  birds.name,
  birds.tag_id,
  birds.species,
  birds.motivators,
  birds.demotivators,
  birds.favorite_snack,
  birds.vet_clinic_name,
  birds.vet_clinic_address,
  birds.vet_account_number,
  birds.vet_doctor_name,
  birds.gender,
  birds.date_of_birth::text,
  birds.gotcha_day::text,
  birds.chart_color,
  birds.photo_data_url,
  birds.photo_object_key,
  birds.photo_content_type,
  birds.photo_updated_at,
  birds.notify_on_dob,
  birds.notify_on_gotcha_day,
  birds.public_profile_code,
  birds.public_profile_enabled,
  birds.memorialized_at,
  birds.memorialized_on::text,
  birds.memorial_note,
  birds.notify_on_memorial_day,
  birds.created_at,
  latest.weight_grams AS latest_weight_grams,
  latest.recorded_on::text AS latest_recorded_on
`;

export const getBirdById = async (birdId: string, workspaceId: number) => {
  const result = await db.query<BirdRow>(
    `SELECT
      ${birdSelectFields}
    FROM birds
    LEFT JOIN LATERAL (
      SELECT weight_grams, recorded_on
      FROM weight_records
      WHERE weight_records.bird_id = birds.id
      ORDER BY recorded_on DESC
      LIMIT 1
    ) latest ON TRUE
    WHERE birds.id = $1
      AND birds.workspace_id = $2`,
    [birdId, workspaceId],
  );

  return result.rows[0] ?? null;
};

export const getBirdByPublicProfileCode = async (publicProfileCode: string) => {
  const result = await db.query<BirdRow>(
    `SELECT
      ${birdSelectFields}
    FROM birds
    LEFT JOIN LATERAL (
      SELECT weight_grams, recorded_on
      FROM weight_records
      WHERE weight_records.bird_id = birds.id
      ORDER BY recorded_on DESC
      LIMIT 1
    ) latest ON TRUE
    WHERE birds.public_profile_code = $1
      AND birds.public_profile_enabled = TRUE
      AND birds.memorialized_at IS NULL`,
    [publicProfileCode],
  );

  return result.rows[0] ?? null;
};

export const listBirds = async (workspaceId: number) => {
  const result = await db.query<BirdRow>(
    `SELECT
      ${birdSelectFields}
    FROM birds
    LEFT JOIN LATERAL (
      SELECT weight_grams, recorded_on
      FROM weight_records
      WHERE weight_records.bird_id = birds.id
      ORDER BY recorded_on DESC
      LIMIT 1
    ) latest ON TRUE
    WHERE birds.workspace_id = $1
      AND birds.memorialized_at IS NULL
    ORDER BY birds.name ASC`,
    [workspaceId],
  );

  return result.rows;
};

export const listMemorializedBirds = async (workspaceId: number) => {
  const result = await db.query<BirdRow>(
    `SELECT
      ${birdSelectFields}
    FROM birds
    LEFT JOIN LATERAL (
      SELECT weight_grams, recorded_on
      FROM weight_records
      WHERE weight_records.bird_id = birds.id
      ORDER BY recorded_on DESC
      LIMIT 1
    ) latest ON TRUE
    WHERE birds.workspace_id = $1
      AND birds.memorialized_at IS NOT NULL
    ORDER BY birds.memorialized_on DESC NULLS LAST, birds.name ASC`,
    [workspaceId],
  );

  return result.rows;
};

export const findBirdsByBandId = async (tagId: string) => {
  const result = await db.query<LostBirdMatchRow>(
    `SELECT
      ${birdSelectFields},
      workspaces.name AS workspace_name,
      workspaces.billing_email AS workspace_billing_email
    FROM birds
    INNER JOIN workspaces ON workspaces.id = birds.workspace_id
    LEFT JOIN LATERAL (
      SELECT weight_grams, recorded_on
      FROM weight_records
      WHERE weight_records.bird_id = birds.id
      ORDER BY recorded_on DESC
      LIMIT 1
    ) latest ON TRUE
     WHERE birds.tag_id IS NOT NULL
      AND BTRIM(birds.tag_id) <> ''
      AND LOWER(BTRIM(birds.tag_id)) NOT IN ('unknown', 'not recorded', 'n/a', 'na', 'none')
      AND LOWER(birds.tag_id) = LOWER($1)
      AND birds.memorialized_at IS NULL
     ORDER BY birds.created_at ASC
     LIMIT 10`,
    [tagId],
  );

  return result.rows;
};

export const listDueBirdMilestoneReminders = async (runDate: string) => {
  const result = await db.query<BirdMilestoneReminderCandidateRow>(
    `WITH reminder_context AS (
       SELECT $1::date AS run_date,
              EXTRACT(YEAR FROM $1::date)::int AS reminder_year
     )
     SELECT
       ${birdSelectFields},
       workspaces.name AS workspace_name,
       'hatch_day'::text AS reminder_type,
       birds.date_of_birth::text AS reminder_date,
       reminder_context.reminder_year
     FROM birds
     INNER JOIN workspaces ON workspaces.id = birds.workspace_id
     CROSS JOIN reminder_context
     LEFT JOIN LATERAL (
       SELECT weight_grams, recorded_on
       FROM weight_records
       WHERE weight_records.bird_id = birds.id
       ORDER BY recorded_on DESC
       LIMIT 1
     ) latest ON TRUE
     WHERE birds.notify_on_dob = TRUE
       AND birds.memorialized_at IS NULL
       AND birds.date_of_birth IS NOT NULL
       AND EXTRACT(MONTH FROM birds.date_of_birth) = EXTRACT(MONTH FROM reminder_context.run_date)
       AND EXTRACT(DAY FROM birds.date_of_birth) = EXTRACT(DAY FROM reminder_context.run_date)
       AND NOT EXISTS (
         SELECT 1
         FROM bird_milestone_reminder_deliveries deliveries
         WHERE deliveries.bird_id = birds.id
           AND deliveries.reminder_type = 'hatch_day'
           AND deliveries.reminder_year = reminder_context.reminder_year
       )
     UNION ALL
     SELECT
       ${birdSelectFields},
       workspaces.name AS workspace_name,
       'gotcha_day'::text AS reminder_type,
       birds.gotcha_day::text AS reminder_date,
       reminder_context.reminder_year
     FROM birds
     INNER JOIN workspaces ON workspaces.id = birds.workspace_id
     CROSS JOIN reminder_context
     LEFT JOIN LATERAL (
       SELECT weight_grams, recorded_on
       FROM weight_records
       WHERE weight_records.bird_id = birds.id
       ORDER BY recorded_on DESC
       LIMIT 1
     ) latest ON TRUE
     WHERE birds.notify_on_gotcha_day = TRUE
       AND birds.memorialized_at IS NULL
       AND birds.gotcha_day IS NOT NULL
       AND EXTRACT(MONTH FROM birds.gotcha_day) = EXTRACT(MONTH FROM reminder_context.run_date)
       AND EXTRACT(DAY FROM birds.gotcha_day) = EXTRACT(DAY FROM reminder_context.run_date)
       AND NOT EXISTS (
         SELECT 1
         FROM bird_milestone_reminder_deliveries deliveries
         WHERE deliveries.bird_id = birds.id
           AND deliveries.reminder_type = 'gotcha_day'
           AND deliveries.reminder_year = reminder_context.reminder_year
       )
     UNION ALL
     SELECT
       ${birdSelectFields},
       workspaces.name AS workspace_name,
       'memorial_day'::text AS reminder_type,
       birds.memorialized_on::text AS reminder_date,
       reminder_context.reminder_year
     FROM birds
     INNER JOIN workspaces ON workspaces.id = birds.workspace_id
     CROSS JOIN reminder_context
     LEFT JOIN LATERAL (
       SELECT weight_grams, recorded_on
       FROM weight_records
       WHERE weight_records.bird_id = birds.id
       ORDER BY recorded_on DESC
       LIMIT 1
     ) latest ON TRUE
     WHERE birds.notify_on_memorial_day = TRUE
       AND birds.memorialized_at IS NOT NULL
       AND birds.memorialized_on IS NOT NULL
       AND EXTRACT(MONTH FROM birds.memorialized_on) = EXTRACT(MONTH FROM reminder_context.run_date)
       AND EXTRACT(DAY FROM birds.memorialized_on) = EXTRACT(DAY FROM reminder_context.run_date)
       AND NOT EXISTS (
         SELECT 1
         FROM bird_milestone_reminder_deliveries deliveries
         WHERE deliveries.bird_id = birds.id
           AND deliveries.reminder_type = 'memorial_day'
           AND deliveries.reminder_year = reminder_context.reminder_year
       )
     ORDER BY workspace_name ASC, name ASC, reminder_type ASC`,
    [runDate],
  );

  return result.rows;
};

export const createBirdMilestoneReminderDelivery = async ({
  birdId,
  workspaceId,
  reminderType,
  reminderYear,
  deliveredOn,
}: {
  birdId: string;
  workspaceId: number;
  reminderType: BirdMilestoneReminderType;
  reminderYear: number;
  deliveredOn: string;
}) => {
  const result = await db.query<BirdMilestoneReminderDeliveryRow>(
    `INSERT INTO bird_milestone_reminder_deliveries (bird_id, workspace_id, reminder_type, reminder_year, delivered_on)
     VALUES ($1, $2, $3, $4, $5)
     ON CONFLICT (bird_id, reminder_type, reminder_year) DO NOTHING
     RETURNING id, bird_id, workspace_id, reminder_type, reminder_year, delivered_on::text, created_at`,
    [birdId, workspaceId, reminderType, reminderYear, deliveredOn],
  );

  return result.rows[0] ?? null;
};

export const createBird = async ({
  birdId,
  workspaceId,
  name,
  tagId,
  species,
  motivators,
  demotivators,
  favoriteSnack,
  vetClinicName = null,
  vetClinicAddress = null,
  vetAccountNumber = null,
  vetDoctorName = null,
  gender,
  dateOfBirth,
  gotchaDay,
  chartColor,
  photoDataUrl,
  photoObjectKey = null,
  photoContentType = null,
  photoUpdatedAt = null,
  notifyOnDob,
  notifyOnGotchaDay,
  publicProfileCode = null,
  publicProfileEnabled = false,
}: {
  birdId?: string;
  workspaceId: number;
  name: string;
  tagId: string | null;
  species: string;
  motivators: string | null;
  demotivators: string | null;
  favoriteSnack: string | null;
  vetClinicName?: string | null;
  vetClinicAddress?: string | null;
  vetAccountNumber?: string | null;
  vetDoctorName?: string | null;
  gender: BirdGender;
  dateOfBirth: string | null;
  gotchaDay: string | null;
  chartColor: string;
  photoDataUrl: string | null;
  photoObjectKey?: string | null;
  photoContentType?: string | null;
  photoUpdatedAt?: string | null;
  notifyOnDob: boolean;
  notifyOnGotchaDay: boolean;
  publicProfileCode?: string | null;
  publicProfileEnabled?: boolean;
}) => {
  const result = await db.query<BirdRow>(
    `INSERT INTO birds (id, workspace_id, name, tag_id, species, motivators, demotivators, favorite_snack, vet_clinic_name, vet_clinic_address, vet_account_number, vet_doctor_name, gender, date_of_birth, gotcha_day, chart_color, photo_data_url, photo_object_key, photo_content_type, photo_updated_at, notify_on_dob, notify_on_gotcha_day, public_profile_code, public_profile_enabled)
     VALUES (COALESCE($1::uuid, gen_random_uuid()), $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24)
     RETURNING id, workspace_id, name, tag_id, species, motivators, demotivators, favorite_snack, vet_clinic_name, vet_clinic_address, vet_account_number, vet_doctor_name, gender, date_of_birth::text, gotcha_day::text, chart_color, photo_data_url, photo_object_key, photo_content_type, photo_updated_at, notify_on_dob, notify_on_gotcha_day, public_profile_code, public_profile_enabled, memorialized_at, memorialized_on::text, memorial_note, notify_on_memorial_day, created_at, NULL::text AS latest_weight_grams, NULL::text AS latest_recorded_on`,
    [
      birdId ?? null,
      workspaceId,
      name,
      tagId,
      species,
      motivators,
      demotivators,
      favoriteSnack,
      vetClinicName,
      vetClinicAddress,
      vetAccountNumber,
      vetDoctorName,
      gender,
      dateOfBirth,
      gotchaDay,
      chartColor,
      photoDataUrl,
      photoObjectKey,
      photoContentType,
      photoUpdatedAt,
      notifyOnDob,
      notifyOnGotchaDay,
      publicProfileCode,
      publicProfileEnabled,
    ],
  );

  return result.rows[0] ?? null;
};

export const updateBird = async ({
  birdId,
  workspaceId,
  name,
  tagId,
  species,
  motivators,
  demotivators,
  favoriteSnack,
  vetClinicName,
  vetClinicAddress,
  vetAccountNumber,
  vetDoctorName,
  gender,
  dateOfBirth,
  gotchaDay,
  chartColor,
  photoDataUrl,
  photoObjectKey = null,
  photoContentType = null,
  photoUpdatedAt = null,
  notifyOnDob,
  notifyOnGotchaDay,
  publicProfileCode,
  publicProfileEnabled,
}: {
  birdId: string;
  workspaceId: number;
  name: string;
  tagId: string | null;
  species: string;
  motivators: string | null;
  demotivators: string | null;
  favoriteSnack: string | null;
  vetClinicName: string | null;
  vetClinicAddress: string | null;
  vetAccountNumber: string | null;
  vetDoctorName: string | null;
  gender: BirdGender;
  dateOfBirth: string | null;
  gotchaDay: string | null;
  chartColor: string;
  photoDataUrl: string | null;
  photoObjectKey?: string | null;
  photoContentType?: string | null;
  photoUpdatedAt?: string | null;
  notifyOnDob: boolean;
  notifyOnGotchaDay: boolean;
  publicProfileCode: string | null;
  publicProfileEnabled: boolean;
}) => {
  const result = await db.query<BirdRow>(
    `UPDATE birds
     SET name = $2,
         tag_id = $3,
         species = $4,
         motivators = $5,
         demotivators = $6,
         favorite_snack = $7,
         vet_clinic_name = $8,
         vet_clinic_address = $9,
         vet_account_number = $10,
         vet_doctor_name = $11,
         gender = $12,
         date_of_birth = $13,
         gotcha_day = $14,
         chart_color = $15,
         photo_data_url = $16,
         photo_object_key = $17,
         photo_content_type = $18,
         photo_updated_at = $19,
         notify_on_dob = $20,
         notify_on_gotcha_day = $21,
         public_profile_code = $22,
         public_profile_enabled = $23
     WHERE id = $1
       AND workspace_id = $24
       AND memorialized_at IS NULL
     RETURNING id, workspace_id, name, tag_id, species, motivators, demotivators, favorite_snack, vet_clinic_name, vet_clinic_address, vet_account_number, vet_doctor_name, gender, date_of_birth::text, gotcha_day::text, chart_color, photo_data_url, photo_object_key, photo_content_type, photo_updated_at, notify_on_dob, notify_on_gotcha_day, public_profile_code, public_profile_enabled, memorialized_at, memorialized_on::text, memorial_note, notify_on_memorial_day, created_at,
       (
         SELECT weight_grams::text
         FROM weight_records
         WHERE bird_id = birds.id
         ORDER BY recorded_on DESC
         LIMIT 1
       ) AS latest_weight_grams,
       (
         SELECT recorded_on::text
         FROM weight_records
         WHERE bird_id = birds.id
         ORDER BY recorded_on DESC
         LIMIT 1
       ) AS latest_recorded_on`,
    [
      birdId,
      name,
      tagId,
      species,
      motivators,
      demotivators,
      favoriteSnack,
      vetClinicName,
      vetClinicAddress,
      vetAccountNumber,
      vetDoctorName,
      gender,
      dateOfBirth,
      gotchaDay,
      chartColor,
      photoDataUrl,
      photoObjectKey,
      photoContentType,
      photoUpdatedAt,
      notifyOnDob,
      notifyOnGotchaDay,
      publicProfileCode,
      publicProfileEnabled,
      workspaceId,
    ],
  );

  return result.rows[0] ?? null;
};

export const memorializeBird = async ({
  birdId,
  workspaceId,
  memorializedOn,
  memorialNote,
  notifyOnMemorialDay,
}: {
  birdId: string;
  workspaceId: number;
  memorializedOn: string;
  memorialNote: string | null;
  notifyOnMemorialDay: boolean;
}) => {
  const result = await db.query<BirdRow>(
    `UPDATE birds
     SET memorialized_at = CURRENT_TIMESTAMP,
         memorialized_on = $3,
         memorial_note = $4,
         notify_on_memorial_day = $5
     WHERE id = $1
       AND workspace_id = $2
       AND memorialized_at IS NULL
     RETURNING id, workspace_id, name, tag_id, species, motivators, demotivators, favorite_snack, vet_clinic_name, vet_clinic_address, vet_account_number, vet_doctor_name, gender, date_of_birth::text, gotcha_day::text, chart_color, photo_data_url, photo_object_key, photo_content_type, photo_updated_at, notify_on_dob, notify_on_gotcha_day, public_profile_code, public_profile_enabled, memorialized_at, memorialized_on::text, memorial_note, notify_on_memorial_day, created_at,
       (
         SELECT weight_grams::text
         FROM weight_records
         WHERE bird_id = birds.id
         ORDER BY recorded_on DESC
         LIMIT 1
       ) AS latest_weight_grams,
       (
         SELECT recorded_on::text
         FROM weight_records
         WHERE bird_id = birds.id
         ORDER BY recorded_on DESC
         LIMIT 1
       ) AS latest_recorded_on`,
    [birdId, workspaceId, memorializedOn, memorialNote, notifyOnMemorialDay],
  );

  return result.rows[0] ?? null;
};

export const updateMemorialReminderPreference = async ({
  birdId,
  workspaceId,
  notifyOnMemorialDay,
}: {
  birdId: string;
  workspaceId: number;
  notifyOnMemorialDay: boolean;
}) => {
  const result = await db.query<BirdRow>(
    `UPDATE birds
     SET notify_on_memorial_day = $3
     WHERE id = $1
       AND workspace_id = $2
       AND memorialized_at IS NOT NULL
     RETURNING id, workspace_id, name, tag_id, species, motivators, demotivators, favorite_snack, vet_clinic_name, vet_clinic_address, vet_account_number, vet_doctor_name, gender, date_of_birth::text, gotcha_day::text, chart_color, photo_data_url, photo_object_key, photo_content_type, photo_updated_at, notify_on_dob, notify_on_gotcha_day, public_profile_code, public_profile_enabled, memorialized_at, memorialized_on::text, memorial_note, notify_on_memorial_day, created_at,
       (
         SELECT weight_grams::text
         FROM weight_records
         WHERE bird_id = birds.id
         ORDER BY recorded_on DESC
         LIMIT 1
       ) AS latest_weight_grams,
       (
         SELECT recorded_on::text
         FROM weight_records
         WHERE bird_id = birds.id
         ORDER BY recorded_on DESC
         LIMIT 1
       ) AS latest_recorded_on`,
    [birdId, workspaceId, notifyOnMemorialDay],
  );

  return result.rows[0] ?? null;
};

export const deleteBird = async (birdId: string, workspaceId: number) => {
  const result = await db.query<{ id: string }>(
    `DELETE FROM birds
     WHERE id = $1
       AND workspace_id = $2
     RETURNING id`,
    [birdId, workspaceId],
  );

  return Boolean(result.rowCount);
};

export const transferBirdToWorkspace = async (birdId: string, sourceWorkspaceId: number, targetWorkspaceId: number) => {
  const result = await db.query<BirdRow>(
    `UPDATE birds
     SET workspace_id = $3
     WHERE id = $1
       AND workspace_id = $2
       AND memorialized_at IS NULL
     RETURNING id, workspace_id, name, tag_id, species, motivators, demotivators, favorite_snack, vet_clinic_name, vet_clinic_address, vet_account_number, vet_doctor_name, gender, date_of_birth::text, gotcha_day::text, chart_color, photo_data_url, photo_object_key, photo_content_type, photo_updated_at, notify_on_dob, notify_on_gotcha_day, public_profile_code, public_profile_enabled, memorialized_at, memorialized_on::text, memorial_note, notify_on_memorial_day, created_at,
       (
         SELECT weight_grams::text
         FROM weight_records
         WHERE bird_id = birds.id
         ORDER BY recorded_on DESC
         LIMIT 1
       ) AS latest_weight_grams,
       (
         SELECT recorded_on::text
         FROM weight_records
         WHERE bird_id = birds.id
         ORDER BY recorded_on DESC
         LIMIT 1
       ) AS latest_recorded_on`,
    [birdId, sourceWorkspaceId, targetWorkspaceId],
  );

  return result.rows[0] ?? null;
};

export const createPendingBirdTransfer = async ({
  birdId,
  sourceWorkspaceId,
  destinationOwnerEmail,
  requestedByUserId,
}: {
  birdId: string;
  sourceWorkspaceId: number;
  destinationOwnerEmail: string;
  requestedByUserId: string;
}) => {
  const result = await db.query<PendingBirdTransferRow>(
    `INSERT INTO pending_bird_transfers (bird_id, source_workspace_id, destination_owner_email, requested_by_user_id)
     VALUES ($1, $2, $3, $4)
     ON CONFLICT (bird_id) WHERE completed_at IS NULL DO UPDATE
     SET destination_owner_email = EXCLUDED.destination_owner_email,
         requested_by_user_id = EXCLUDED.requested_by_user_id,
         last_error = NULL,
         created_at = CURRENT_TIMESTAMP
     RETURNING id, bird_id, source_workspace_id, destination_owner_email, requested_by_user_id, completed_at::text, completed_workspace_id, last_error, created_at`,
    [birdId, sourceWorkspaceId, destinationOwnerEmail, requestedByUserId],
  );

  return result.rows[0] ?? null;
};

export const listPendingBirdTransfersForOwnerEmail = async (ownerEmail: string) => {
  const result = await db.query<PendingBirdTransferRow>(
    `SELECT id, bird_id, source_workspace_id, destination_owner_email, requested_by_user_id, completed_at::text, completed_workspace_id, last_error, created_at
     FROM pending_bird_transfers
     WHERE LOWER(destination_owner_email) = LOWER($1)
       AND completed_at IS NULL
     ORDER BY created_at ASC`,
    [ownerEmail],
  );

  return result.rows;
};

export const markPendingBirdTransferCompleted = async (transferId: string, completedWorkspaceId: number) => {
  await db.query(
    `UPDATE pending_bird_transfers
     SET completed_at = CURRENT_TIMESTAMP,
         completed_workspace_id = $2,
         last_error = NULL
     WHERE id = $1`,
    [transferId, completedWorkspaceId],
  );
};

export const markPendingBirdTransferFailed = async (transferId: string, lastError: string) => {
  await db.query(
    `UPDATE pending_bird_transfers
     SET last_error = $2
     WHERE id = $1`,
    [transferId, lastError],
  );
};

export const completePendingBirdTransfersForOwner = async (ownerEmail: string, targetWorkspaceId: number) => {
  const transfers = await listPendingBirdTransfersForOwnerEmail(ownerEmail);
  let completed = 0;
  let failed = 0;

  for (const transfer of transfers) {
    try {
      const bird = await transferBirdToWorkspace(transfer.bird_id, transfer.source_workspace_id, targetWorkspaceId);

      if (!bird) {
        failed += 1;
        await markPendingBirdTransferFailed(transfer.id, 'Bird is no longer available in the source flock.');
        continue;
      }

      await markPendingBirdTransferCompleted(transfer.id, targetWorkspaceId);
      completed += 1;
    } catch (error) {
      failed += 1;
      const message =
        typeof error === 'object' && error && 'code' in error && error.code === '23505'
          ? 'That band/tag ID is already in use in FlockPal.'
          : error instanceof Error
            ? error.message
            : 'Unable to complete pending bird transfer.';
      await markPendingBirdTransferFailed(transfer.id, message);
    }
  }

  return { completed, failed };
};

export const createBirdTransferCode = async ({
  code,
  birdId,
  sourceWorkspaceId,
  requestedByUserId,
}: {
  code: string;
  birdId: string;
  sourceWorkspaceId: number;
  requestedByUserId: string;
}) => {
  await db.query(
    `UPDATE bird_transfer_codes
     SET revoked_at = CURRENT_TIMESTAMP
     WHERE bird_id = $1
       AND source_workspace_id = $2
       AND completed_at IS NULL
       AND revoked_at IS NULL`,
    [birdId, sourceWorkspaceId],
  );

  const result = await db.query<BirdTransferCodeRow>(
    `INSERT INTO bird_transfer_codes (code, bird_id, source_workspace_id, requested_by_user_id)
     VALUES ($1, $2, $3, $4)
     RETURNING id, code, bird_id, source_workspace_id, requested_by_user_id, completed_at::text, completed_workspace_id, revoked_at::text, created_at`,
    [code, birdId, sourceWorkspaceId, requestedByUserId],
  );

  return result.rows[0] ?? null;
};

export const getOpenBirdTransferCode = async (code: string) => {
  const result = await db.query<
    BirdRow & {
      transfer_code_id: string;
      code: string;
      source_workspace_id: number;
      requested_by_user_id: string;
      completed_at: string | null;
      completed_workspace_id: number | null;
      revoked_at: string | null;
      transfer_code_created_at: string;
      workspace_name: string;
    }
  >(
    `SELECT
       bird_transfer_codes.id AS transfer_code_id,
       bird_transfer_codes.code,
       bird_transfer_codes.source_workspace_id,
       bird_transfer_codes.requested_by_user_id,
       bird_transfer_codes.completed_at::text,
       bird_transfer_codes.completed_workspace_id,
       bird_transfer_codes.revoked_at::text,
       bird_transfer_codes.created_at AS transfer_code_created_at,
       workspaces.name AS workspace_name,
       ${birdSelectFields}
     FROM bird_transfer_codes
     INNER JOIN birds ON birds.id = bird_transfer_codes.bird_id
     INNER JOIN workspaces ON workspaces.id = bird_transfer_codes.source_workspace_id
     LEFT JOIN LATERAL (
       SELECT weight_grams, recorded_on
       FROM weight_records
       WHERE weight_records.bird_id = birds.id
       ORDER BY recorded_on DESC
       LIMIT 1
     ) latest ON TRUE
     WHERE bird_transfer_codes.code = $1
       AND bird_transfer_codes.completed_at IS NULL
       AND bird_transfer_codes.revoked_at IS NULL
       AND birds.workspace_id = bird_transfer_codes.source_workspace_id
       AND birds.memorialized_at IS NULL`,
    [code],
  );

  return result.rows[0] ?? null;
};

export const markBirdTransferCodeCompleted = async (codeId: string, completedWorkspaceId: number) => {
  await db.query(
    `UPDATE bird_transfer_codes
     SET completed_at = CURRENT_TIMESTAMP,
         completed_workspace_id = $2
     WHERE id = $1`,
    [codeId, completedWorkspaceId],
  );
};

export const listWeightsForBird = async (birdId: string, workspaceId: number, days: number) => {
  const result = await db.query<WeightRow>(
    `SELECT id, bird_id, weight_grams, recorded_on::text, notes
     FROM weight_records
     WHERE bird_id = $1
       AND EXISTS (
         SELECT 1
         FROM birds
         WHERE birds.id = weight_records.bird_id
           AND birds.workspace_id = $3
       )
       AND recorded_on >= CURRENT_DATE - (($2::int - 1) * INTERVAL '1 day')
     ORDER BY recorded_on ASC`,
    [birdId, days, workspaceId],
  );

  return result.rows;
};

export const createWeightForBird = async (birdId: string, weightGrams: number, recordedOn: string, notes: string | null) => {
  const result = await db.query<WeightRow>(
    `INSERT INTO weight_records (bird_id, weight_grams, recorded_on, notes)
     VALUES ($1, $2, $3, $4)
     RETURNING id, bird_id, weight_grams, recorded_on::text, notes`,
    [birdId, weightGrams, recordedOn, notes],
  );

  return result.rows[0] ?? null;
};

export const listVetVisitsForBird = async (birdId: string, workspaceId: number) => {
  const result = await db.query<VetVisitRow>(
    `SELECT id, bird_id, visited_on::text, clinic_name, reason, notes
     FROM vet_visits
     WHERE bird_id = $1
       AND EXISTS (
         SELECT 1
         FROM birds
         WHERE birds.id = vet_visits.bird_id
           AND birds.workspace_id = $2
       )
     ORDER BY visited_on DESC, created_at DESC`,
    [birdId, workspaceId],
  );

  return result.rows;
};

export const createVetVisitForBird = async (birdId: string, visitedOn: string, clinicName: string, reason: string, notes: string | null) => {
  const result = await db.query<VetVisitRow>(
    `INSERT INTO vet_visits (bird_id, visited_on, clinic_name, reason, notes)
     VALUES ($1, $2, $3, $4, $5)
     RETURNING id, bird_id, visited_on::text, clinic_name, reason, notes`,
    [birdId, visitedOn, clinicName, reason, notes],
  );

  return result.rows[0] ?? null;
};

export const updateVetVisitForBird = async (
  visitId: string,
  birdId: string,
  visitedOn: string,
  clinicName: string,
  reason: string,
  notes: string | null,
) => {
  const result = await db.query<VetVisitRow>(
    `UPDATE vet_visits
     SET visited_on = $3,
         clinic_name = $4,
         reason = $5,
         notes = $6
     WHERE id = $1
       AND bird_id = $2
     RETURNING id, bird_id, visited_on::text, clinic_name, reason, notes`,
    [visitId, birdId, visitedOn, clinicName, reason, notes],
  );

  return result.rows[0] ?? null;
};

export const deleteVetVisitForBird = async (visitId: string, birdId: string) => {
  const result = await db.query<{ id: string }>(
    `DELETE FROM vet_visits
     WHERE id = $1
       AND bird_id = $2
     RETURNING id`,
    [visitId, birdId],
  );

  return (result.rowCount ?? 0) > 0;
};

export const listMedicationsForBird = async (birdId: string, workspaceId: number) => {
  const result = await db.query<MedicationRow>(
    `SELECT id, bird_id, name, dosage, frequency, dose_schedule, route, start_date::text, end_date::text, notes
     FROM medications
     WHERE bird_id = $1
       AND EXISTS (
         SELECT 1
         FROM birds
         WHERE birds.id = medications.bird_id
           AND birds.workspace_id = $2
       )
     ORDER BY COALESCE(end_date, '9999-12-31'::date) DESC, start_date DESC, created_at DESC`,
    [birdId, workspaceId],
  );

  return result.rows;
};

export const createMedicationForBird = async (
  birdId: string,
  name: string,
  dosage: string,
  frequency: string,
  doseSchedule: MedicationDoseScheduleItem[],
  route: string | null,
  startDate: string,
  endDate: string | null,
  notes: string | null,
) => {
  const result = await db.query<MedicationRow>(
    `INSERT INTO medications (bird_id, name, dosage, frequency, dose_schedule, route, start_date, end_date, notes)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
     RETURNING id, bird_id, name, dosage, frequency, dose_schedule, route, start_date::text, end_date::text, notes`,
    [birdId, name, dosage, frequency, JSON.stringify(doseSchedule), route, startDate, endDate, notes],
  );

  return result.rows[0] ?? null;
};

export const updateMedicationForBird = async (
  medicationId: string,
  birdId: string,
  name: string,
  dosage: string,
  frequency: string,
  doseSchedule: MedicationDoseScheduleItem[],
  route: string | null,
  startDate: string,
  endDate: string | null,
  notes: string | null,
) => {
  const result = await db.query<MedicationRow>(
    `UPDATE medications
     SET name = $3,
         dosage = $4,
         frequency = $5,
         dose_schedule = $6,
         route = $7,
         start_date = $8,
         end_date = $9,
         notes = $10
     WHERE id = $1
       AND bird_id = $2
     RETURNING id, bird_id, name, dosage, frequency, dose_schedule, route, start_date::text, end_date::text, notes`,
    [medicationId, birdId, name, dosage, frequency, JSON.stringify(doseSchedule), route, startDate, endDate, notes],
  );

  return result.rows[0] ?? null;
};

export const deleteMedicationForBird = async (medicationId: string, birdId: string) => {
  const result = await db.query<{ id: string }>(
    `DELETE FROM medications
     WHERE id = $1
       AND bird_id = $2
     RETURNING id`,
    [medicationId, birdId],
  );

  return (result.rowCount ?? 0) > 0;
};

export const listMedicationAdministrationsForBird = async (birdId: string, workspaceId: number) => {
  const result = await db.query<MedicationAdministrationRow>(
    `SELECT id, medication_id, bird_id, administered_on::text, administration_slot, status, notes, created_by_user_id, created_at
     FROM medication_administrations
     WHERE bird_id = $1
       AND EXISTS (
         SELECT 1
         FROM birds
         WHERE birds.id = medication_administrations.bird_id
           AND birds.workspace_id = $2
       )
     ORDER BY administered_on DESC, created_at DESC`,
    [birdId, workspaceId],
  );

  return result.rows;
};

export const upsertMedicationAdministrationForBird = async (
  medicationId: string,
  birdId: string,
  workspaceId: number,
  administeredOn: string,
  administrationSlot: string,
  status: 'administered' | 'missed',
  notes: string | null,
  createdByUserId: string | null,
) => {
  const result = await db.query<MedicationAdministrationRow>(
    `INSERT INTO medication_administrations (medication_id, bird_id, administered_on, administration_slot, status, notes, created_by_user_id)
     SELECT $1, $2, $4, $5, $6, $7, $8
     WHERE EXISTS (
       SELECT 1
       FROM medications
       JOIN birds ON birds.id = medications.bird_id
       WHERE medications.id = $1
         AND medications.bird_id = $2
         AND birds.workspace_id = $3
     )
     ON CONFLICT (medication_id, administered_on, administration_slot)
     DO UPDATE SET status = EXCLUDED.status,
                   notes = EXCLUDED.notes,
                   created_by_user_id = EXCLUDED.created_by_user_id,
                   created_at = CURRENT_TIMESTAMP
     RETURNING id, medication_id, bird_id, administered_on::text, administration_slot, status, notes, created_by_user_id, created_at`,
    [medicationId, birdId, workspaceId, administeredOn, administrationSlot, status, notes, createdByUserId],
  );

  return result.rows[0] ?? null;
};
