import { db } from '../db/client.js';
import type { BillingInterval, BillingPlan, RescueVerificationStatus, SubscriptionStatus, UserRow, WorkspaceMemberRow, WorkspaceRow, WorkspaceType } from '../types.js';

export const getNextWorkspaceId = async () => {
  const result = await db.query<{ next_id: number }>('SELECT COALESCE(MAX(id), 0) + 1 AS next_id FROM workspaces');
  return Number(result.rows[0]?.next_id ?? 1);
};

export const getWorkspaceById = async (workspaceId: number) => {
  const result = await db.query<WorkspaceRow>(
    `SELECT id, name, workspace_type, billing_email, billing_plan, billing_interval, subscription_status, stripe_customer_id, stripe_subscription_id, rescue_verification_status, created_at, updated_at
     FROM workspaces
     WHERE id = $1`,
    [workspaceId],
  );

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

export const getMembershipForUser = async (userId: string, workspaceId: number) => {
  const result = await db.query<WorkspaceMemberRow>(
    `SELECT id, workspace_id, user_id, COALESCE(invite_email, email) AS invite_email, name, role, accepted_at::text, created_at
     FROM workspace_members
     WHERE workspace_id = $1
       AND user_id = $2`,
    [workspaceId, userId],
  );

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

export const listMembershipsForUser = async (userId: string) => {
  const result = await db.query<
    WorkspaceMemberRow & {
      workspace_name: string;
      workspace_type: WorkspaceType;
      billing_email: string | null;
      billing_plan: BillingPlan;
      billing_interval: BillingInterval;
      subscription_status: WorkspaceRow['subscription_status'];
      stripe_customer_id: string | null;
      stripe_subscription_id: string | null;
      rescue_verification_status: RescueVerificationStatus;
      workspace_created_at: string;
      workspace_updated_at: string;
    }
  >(
    `SELECT
      workspace_members.id,
      workspace_members.workspace_id,
      workspace_members.user_id,
      COALESCE(workspace_members.invite_email, workspace_members.email) AS invite_email,
      workspace_members.name,
      workspace_members.role,
      workspace_members.accepted_at::text,
      workspace_members.created_at,
      workspaces.name AS workspace_name,
      workspaces.workspace_type,
      workspaces.billing_email,
      workspaces.billing_plan,
      workspaces.billing_interval,
      workspaces.subscription_status,
      workspaces.stripe_customer_id,
      workspaces.stripe_subscription_id,
      workspaces.rescue_verification_status,
      workspaces.created_at AS workspace_created_at,
      workspaces.updated_at AS workspace_updated_at
    FROM workspace_members
    INNER JOIN workspaces ON workspaces.id = workspace_members.workspace_id
    WHERE workspace_members.user_id = $1
    ORDER BY workspaces.created_at ASC`,
    [userId],
  );

  return result.rows;
};

export const ensurePersonalWorkspaceForUser = async (user: UserRow) => {
  const existing = await db.query<{ workspace_id: number }>(
    `SELECT workspace_id
     FROM workspace_members
     INNER JOIN workspaces ON workspaces.id = workspace_members.workspace_id
     WHERE workspace_members.user_id = $1
       AND workspaces.workspace_type = 'standard'
     ORDER BY workspaces.created_at ASC
     LIMIT 1`,
    [user.id],
  );

  if (existing.rowCount) {
    return Number(existing.rows[0].workspace_id);
  }

  const workspaceId = await getNextWorkspaceId();

  await db.query(
    `INSERT INTO workspaces (id, name, workspace_type, billing_plan, billing_interval, billing_email, subscription_status, rescue_verification_status)
     VALUES ($1, $2, 'standard', 'household_basic', 'monthly', $3, 'none', 'not_required')`,
    [workspaceId, `${user.name}'s Flock`, user.email],
  );

  await db.query(
    `INSERT INTO workspace_members (workspace_id, user_id, email, invite_email, name, role, accepted_at)
     VALUES ($1, $2, $3, $3, $4, 'owner', CURRENT_TIMESTAMP)
     ON CONFLICT (workspace_id, invite_email) DO UPDATE
     SET user_id = EXCLUDED.user_id,
         email = EXCLUDED.email,
         name = EXCLUDED.name,
         role = 'owner',
         accepted_at = CURRENT_TIMESTAMP`,
    [workspaceId, user.id, user.email, user.name],
  );

  return workspaceId;
};

export const ensureDefaultWorkspaceForUser = async (user: UserRow) => {
  const existing = await db.query<{ workspace_id: number }>(
    `SELECT workspace_id
     FROM workspace_members
     INNER JOIN workspaces ON workspaces.id = workspace_members.workspace_id
     WHERE workspace_members.user_id = $1
     ORDER BY workspaces.created_at ASC
     LIMIT 1`,
    [user.id],
  );

  if (existing.rowCount) {
    return Number(existing.rows[0].workspace_id);
  }

  return ensurePersonalWorkspaceForUser(user);
};

export const claimWorkspaceInvites = async (user: UserRow) => {
  await db.query(
    `UPDATE workspace_members
     SET user_id = $1,
         accepted_at = CURRENT_TIMESTAMP
     WHERE LOWER(COALESCE(invite_email, email)) = LOWER($2)
       AND user_id IS NULL`,
    [user.id, user.email],
  );
};

export const createWorkspace = async ({
  id,
  name,
  workspaceType,
  billingEmail,
  billingPlan,
  billingInterval,
  owner,
}: {
  id: number;
  name: string;
  workspaceType: WorkspaceType;
  billingEmail: string | null;
  billingPlan: BillingPlan;
  billingInterval: BillingInterval;
  owner: UserRow;
}) => {
  await db.query(
    `INSERT INTO workspaces (id, name, workspace_type, billing_email, billing_plan, billing_interval, subscription_status, rescue_verification_status)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
    [
      id,
      name,
      workspaceType,
      billingEmail,
      billingPlan,
      billingInterval,
      workspaceType === 'rescue' ? 'active' : 'none',
      workspaceType === 'rescue' ? 'pending' : 'not_required',
    ],
  );

  await db.query(
    `INSERT INTO workspace_members (workspace_id, user_id, email, invite_email, name, role, accepted_at)
     VALUES ($1, $2, $3, $3, $4, 'owner', CURRENT_TIMESTAMP)`,
    [id, owner.id, owner.email, owner.name],
  );

  return getWorkspaceById(id);
};

export const updateWorkspace = async ({
  workspaceId,
  name,
  workspaceType,
  billingEmail,
  billingPlan,
  billingInterval,
}: {
  workspaceId: number;
  name: string;
  workspaceType: WorkspaceType;
  billingEmail: string | null;
  billingPlan: BillingPlan;
  billingInterval: BillingInterval;
}) => {
  const result = await db.query<WorkspaceRow>(
    `WITH input AS (
       SELECT
         $1::integer AS workspace_id,
         $2::varchar AS name,
         $3::varchar AS workspace_type,
         $4::varchar AS billing_email,
         $5::varchar AS billing_plan,
         $6::varchar AS billing_interval
     )
     UPDATE workspaces
     SET name = input.name,
         workspace_type = input.workspace_type,
         billing_email = input.billing_email,
         billing_plan = input.billing_plan,
         billing_interval = input.billing_interval,
         rescue_verification_status = CASE
           WHEN input.workspace_type = 'rescue' AND workspaces.rescue_verification_status = 'not_required' THEN 'pending'
           WHEN input.workspace_type = 'standard' THEN 'not_required'
           ELSE workspaces.rescue_verification_status
         END,
         updated_at = CURRENT_TIMESTAMP
     FROM input
     WHERE workspaces.id = input.workspace_id
     RETURNING workspaces.id, workspaces.name, workspaces.workspace_type, workspaces.billing_email, workspaces.billing_plan, workspaces.billing_interval, workspaces.subscription_status, workspaces.stripe_customer_id, workspaces.stripe_subscription_id, workspaces.rescue_verification_status, workspaces.created_at, workspaces.updated_at`,
    [workspaceId, name, workspaceType, billingEmail, billingPlan, billingInterval],
  );

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

export const listWorkspaceMembers = async (workspaceId: number) => {
  const result = await db.query<WorkspaceMemberRow>(
    `SELECT id, workspace_id, user_id, COALESCE(invite_email, email) AS invite_email, name, role, accepted_at::text, created_at
     FROM workspace_members
     WHERE workspace_id = $1
     ORDER BY created_at ASC`,
    [workspaceId],
  );

  return result.rows;
};

export const listWorkspaceNotificationEmails = async (workspaceId: number) => {
  const result = await db.query<{ email: string }>(
    `SELECT DISTINCT LOWER(TRIM(email)) AS email
     FROM (
       SELECT COALESCE(invite_email, email) AS email
       FROM workspace_members
       WHERE workspace_id = $1
       UNION
       SELECT billing_email AS email
       FROM workspaces
       WHERE id = $1
     ) contact_emails
     WHERE email IS NOT NULL
       AND TRIM(email) <> ''
     ORDER BY email ASC`,
    [workspaceId],
  );

  return result.rows.map((row) => row.email);
};

export const findAlternateWorkspaceForUser = async (userId: string, excludeWorkspaceId: number) => {
  const result = await db.query<{ workspace_id: number }>(
    `SELECT workspace_id
     FROM workspace_members
     WHERE user_id = $1
       AND workspace_id <> $2
     ORDER BY created_at ASC
     LIMIT 1`,
    [userId, excludeWorkspaceId],
  );

  return result.rows[0] ? Number(result.rows[0].workspace_id) : null;
};

export const listOwnedWorkspacesByOwnerEmail = async (ownerEmail: string, excludeWorkspaceId: number) => {
  const result = await db.query<WorkspaceRow>(
    `SELECT workspaces.id, workspaces.name, workspaces.workspace_type, workspaces.billing_email, workspaces.billing_plan, workspaces.billing_interval, workspaces.subscription_status, workspaces.stripe_customer_id, workspaces.stripe_subscription_id, workspaces.rescue_verification_status, workspaces.created_at, workspaces.updated_at
     FROM workspace_members
     INNER JOIN workspaces ON workspaces.id = workspace_members.workspace_id
     WHERE LOWER(COALESCE(workspace_members.invite_email, workspace_members.email)) = LOWER($1)
       AND workspace_members.role = 'owner'
       AND workspace_members.accepted_at IS NOT NULL
       AND workspaces.id <> $2
     ORDER BY workspaces.created_at ASC`,
    [ownerEmail, excludeWorkspaceId],
  );

  return result.rows;
};

export const getWorkspaceBirdCount = async (workspaceId: number) => {
  const birdCount = await db.query<{ count: string }>(
    `SELECT COUNT(*)::text AS count
     FROM birds
     WHERE workspace_id = $1
       AND memorialized_at IS NULL`,
    [workspaceId],
  );

  return Number(birdCount.rows[0]?.count ?? 0);
};

export const getWorkspaceTotalBirdCount = async (workspaceId: number) => {
  const birdCount = await db.query<{ count: string }>(
    `SELECT COUNT(*)::text AS count
     FROM birds
     WHERE workspace_id = $1`,
    [workspaceId],
  );

  return Number(birdCount.rows[0]?.count ?? 0);
};

export const deleteWorkspaceIfEmpty = async (workspaceId: number) => {
  if ((await getWorkspaceTotalBirdCount(workspaceId)) > 0) {
    return { deleted: false as const, reason: 'birds_present' as const };
  }

  const deleted = await db.query<{ id: number }>(
    `DELETE FROM workspaces
     WHERE id = $1
     RETURNING id`,
    [workspaceId],
  );

  if (!deleted.rowCount) {
    return { deleted: false as const, reason: 'not_found' as const };
  }

  return { deleted: true as const };
};

export const upsertWorkspaceMember = async ({
  workspaceId,
  inviteEmail,
  name,
  role,
  existingUser,
}: {
  workspaceId: number;
  inviteEmail: string;
  name: string;
  role: WorkspaceMemberRow['role'];
  existingUser: UserRow | null;
}) => {
  const result = await db.query<WorkspaceMemberRow>(
    `INSERT INTO workspace_members (workspace_id, user_id, email, invite_email, name, role, accepted_at)
     VALUES ($1, $2, $3, $3, $4, $5, $6)
     ON CONFLICT (workspace_id, invite_email) DO UPDATE
     SET name = EXCLUDED.name,
         role = EXCLUDED.role,
         email = EXCLUDED.email,
         user_id = COALESCE(workspace_members.user_id, EXCLUDED.user_id),
         accepted_at = COALESCE(workspace_members.accepted_at, EXCLUDED.accepted_at)
     RETURNING id, workspace_id, user_id, COALESCE(invite_email, email) AS invite_email, name, role, accepted_at::text, created_at`,
    [workspaceId, existingUser?.id ?? null, inviteEmail, name, role, existingUser ? new Date().toISOString() : null],
  );

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

export const deleteWorkspaceMember = async (memberId: string, workspaceId: number) => {
  const result = await db.query<{ id: string }>(
    `DELETE FROM workspace_members
     WHERE id = $1
       AND workspace_id = $2
       AND role <> 'owner'
     RETURNING id`,
    [memberId, workspaceId],
  );

  return Boolean(result.rowCount);
};

export const listRescueWorkspacesForAdmin = async () => {
  const result = await db.query<
    WorkspaceRow & {
      bird_count: number;
      member_count: number;
    }
  >(
    `SELECT
       workspaces.id,
       workspaces.name,
       workspaces.workspace_type,
       workspaces.billing_email,
       workspaces.billing_plan,
       workspaces.billing_interval,
       workspaces.subscription_status,
       workspaces.stripe_customer_id,
       workspaces.stripe_subscription_id,
       workspaces.rescue_verification_status,
       workspaces.created_at,
       workspaces.updated_at,
       COUNT(DISTINCT birds.id)::int AS bird_count,
       COUNT(DISTINCT workspace_members.id)::int AS member_count
     FROM workspaces
     LEFT JOIN birds ON birds.workspace_id = workspaces.id
     LEFT JOIN workspace_members ON workspace_members.workspace_id = workspaces.id
     WHERE workspaces.workspace_type = 'rescue'
     GROUP BY workspaces.id
     ORDER BY
       CASE workspaces.rescue_verification_status
         WHEN 'pending' THEN 0
         WHEN 'approved' THEN 1
         WHEN 'rejected' THEN 2
         ELSE 3
       END,
       workspaces.created_at DESC`,
  );

  return result.rows;
};

export const updateRescueVerificationStatus = async (workspaceId: number, status: RescueVerificationStatus) => {
  const result = await db.query<WorkspaceRow>(
    `UPDATE workspaces
     SET workspace_type = CASE
           WHEN $2 = 'rejected' THEN 'standard'
           ELSE workspace_type
         END,
         billing_plan = CASE
           WHEN $2 = 'rejected' THEN 'household_basic'
           ELSE billing_plan
         END,
         billing_interval = CASE
           WHEN $2 = 'rejected' THEN 'monthly'
           ELSE billing_interval
         END,
         subscription_status = CASE
           WHEN $2 = 'rejected' THEN 'none'
           ELSE subscription_status
         END,
         rescue_verification_status = CASE
           WHEN $2 = 'rejected' THEN 'not_required'
           ELSE $2
         END,
         updated_at = CURRENT_TIMESTAMP
     WHERE id = $1
       AND workspace_type = 'rescue'
     RETURNING id, name, workspace_type, billing_email, billing_plan, billing_interval, subscription_status, stripe_customer_id, stripe_subscription_id, rescue_verification_status, created_at, updated_at`,
    [workspaceId, status],
  );

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

export const cancelRescueVerificationRequest = async (workspaceId: number) => {
  const result = await db.query<WorkspaceRow>(
    `UPDATE workspaces
     SET workspace_type = 'standard',
         billing_plan = 'household_basic',
         billing_interval = 'monthly',
         subscription_status = 'none',
         rescue_verification_status = 'not_required',
         updated_at = CURRENT_TIMESTAMP
     WHERE id = $1
       AND workspace_type = 'rescue'
       AND rescue_verification_status = 'pending'
     RETURNING id, name, workspace_type, billing_email, billing_plan, billing_interval, subscription_status, stripe_customer_id, stripe_subscription_id, rescue_verification_status, created_at, updated_at`,
    [workspaceId],
  );

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

export const setWorkspaceStripeCustomerId = async (workspaceId: number, stripeCustomerId: string) => {
  const result = await db.query<WorkspaceRow>(
    `UPDATE workspaces
     SET stripe_customer_id = $2,
         updated_at = CURRENT_TIMESTAMP
     WHERE id = $1
     RETURNING id, name, workspace_type, billing_email, billing_plan, billing_interval, subscription_status, stripe_customer_id, stripe_subscription_id, rescue_verification_status, created_at, updated_at`,
    [workspaceId, stripeCustomerId],
  );

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

export const setWorkspaceStripeSubscription = async ({
  workspaceId,
  stripeCustomerId,
  stripeSubscriptionId,
  subscriptionStatus,
  billingPlan,
  billingInterval,
}: {
  workspaceId: number;
  stripeCustomerId: string | null;
  stripeSubscriptionId: string;
  subscriptionStatus: SubscriptionStatus;
  billingPlan?: BillingPlan | null;
  billingInterval?: BillingInterval | null;
}) => {
  const result = await db.query<WorkspaceRow>(
    `UPDATE workspaces
     SET stripe_customer_id = COALESCE($2, stripe_customer_id),
         stripe_subscription_id = $3,
         subscription_status = $4,
         billing_plan = COALESCE($5, billing_plan),
         billing_interval = COALESCE($6, billing_interval),
         updated_at = CURRENT_TIMESTAMP
     WHERE id = $1
     RETURNING id, name, workspace_type, billing_email, billing_plan, billing_interval, subscription_status, stripe_customer_id, stripe_subscription_id, rescue_verification_status, created_at, updated_at`,
    [workspaceId, stripeCustomerId, stripeSubscriptionId, subscriptionStatus, billingPlan ?? null, billingInterval ?? null],
  );

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

export const setWorkspaceSubscriptionStatusByStripeSubscriptionId = async (
  stripeSubscriptionId: string,
  subscriptionStatus: SubscriptionStatus,
  billingPlan?: BillingPlan | null,
  billingInterval?: BillingInterval | null,
) => {
  const result = await db.query<WorkspaceRow>(
    `UPDATE workspaces
     SET subscription_status = $2,
         billing_plan = COALESCE($3, billing_plan),
         billing_interval = COALESCE($4, billing_interval),
         updated_at = CURRENT_TIMESTAMP
     WHERE stripe_subscription_id = $1
     RETURNING id, name, workspace_type, billing_email, billing_plan, billing_interval, subscription_status, stripe_customer_id, stripe_subscription_id, rescue_verification_status, created_at, updated_at`,
    [stripeSubscriptionId, subscriptionStatus, billingPlan ?? null, billingInterval ?? null],
  );

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

export const getPlatformAdminSummary = async () => {
  const result = await db.query<{
    total_birds: number;
    memorialized_birds: number;
    total_users: number;
    total_workspaces: number;
    rescue_workspaces: number;
    rescue_birds: number;
    pending_rescues: number;
    daily_users: number;
  }>(
    `SELECT
       (SELECT COUNT(*)::int FROM birds) AS total_birds,
       (SELECT COUNT(*)::int FROM birds WHERE memorialized_at IS NOT NULL) AS memorialized_birds,
       (SELECT COUNT(*)::int FROM users) AS total_users,
       (SELECT COUNT(*)::int FROM workspaces) AS total_workspaces,
       (SELECT COUNT(*)::int FROM workspaces WHERE workspace_type = 'rescue') AS rescue_workspaces,
       (SELECT COUNT(*)::int FROM birds INNER JOIN workspaces ON workspaces.id = birds.workspace_id WHERE workspaces.workspace_type = 'rescue') AS rescue_birds,
       (SELECT COUNT(*)::int FROM workspaces WHERE workspace_type = 'rescue' AND rescue_verification_status = 'pending') AS pending_rescues,
       (SELECT COUNT(DISTINCT user_id)::int FROM auth_sessions WHERE created_at >= CURRENT_DATE) AS daily_users`,
  );

  return result.rows[0];
};
