/**
 * Rate card lookup logic for auto-filling demand line rates.
 *
 * Match priority (highest specificity wins):
 *   1. Exact client + chapter + role
 *   2. Client + chapter (any role)
 *   3. Client + role (any chapter)
 *   4. Client only (fallback)
 *   5. Default rate card (no client) + best match
 *
 * Within each priority tier, additional criteria (seniority, location,
 * workType) increase the score.
 */

export interface RateCardLookupParams {
  clientId?: string | null;
  chapter?: string | null;
  roleId?: string | null;
  seniority?: string | null;
  location?: string | null;
  workType?: string | null;
  effectiveDate?: Date | null;
}

export interface RateCardLookupResult {
  costRateCents: number;
  billRateCents: number;
  currency: string;
  rateCardId: string;
  rateCardLineId: string;
  rateCardName: string;
}

interface RateCardLineRow {
  id: string;
  rateCardId: string;
  roleId: string | null;
  chapter: string | null;
  location: string | null;
  seniority: string | null;
  workType: string | null;
  costRateCents: number;
  billRateCents: number | null;
  rateCard: {
    id: string;
    name: string;
    currency: string;
    clientId: string | null;
  };
}

/**
 * Look up the best-matching rate card line for a given set of criteria.
 * Returns null when no active rate card line matches.
 */
export async function lookupRate(
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  db: any,
  params: RateCardLookupParams,
): Promise<RateCardLookupResult | null> {
  const effectiveDate = params.effectiveDate ?? new Date();

  // Build rate card filter: active cards, within effective date range
  const rateCardWhere: Record<string, unknown> = {
    isActive: true,
    OR: [
      { effectiveFrom: null },
      { effectiveFrom: { lte: effectiveDate } },
    ],
    AND: [
      {
        OR: [
          { effectiveTo: null },
          { effectiveTo: { gte: effectiveDate } },
        ],
      },
    ],
  };

  // If we have a clientId, look for both client-specific and default (null client) cards
  if (params.clientId) {
    rateCardWhere.clientId = { in: [params.clientId, null] };
  }
  // If no clientId, only look at default (null client) cards
  // (don't pass clientId filter at all to keep the OR above valid)

  const lines = (await db.rateCardLine.findMany({
    where: {
      rateCard: rateCardWhere,
    },
    select: {
      id: true,
      rateCardId: true,
      roleId: true,
      chapter: true,
      location: true,
      seniority: true,
      workType: true,
      costRateCents: true,
      billRateCents: true,
      rateCard: {
        select: {
          id: true,
          name: true,
          currency: true,
          clientId: true,
        },
      },
    },
  })) as RateCardLineRow[];

  if (lines.length === 0) return null;

  // Score each line. Higher = better match.
  type ScoredLine = { line: RateCardLineRow; score: number; mismatch: boolean };
  const scored: ScoredLine[] = lines.map((line) => {
    let score = 0;
    let mismatch = false;

    // Client specificity: client-specific cards get a large bonus
    if (params.clientId && line.rateCard.clientId === params.clientId) {
      score += 100;
    } else if (params.clientId && line.rateCard.clientId != null) {
      // Different client entirely => disqualify
      mismatch = true;
    }
    // Default card (null client) gets no bonus but is a valid fallback

    // Role match
    if (params.roleId && line.roleId) {
      if (line.roleId === params.roleId) score += 16;
      else mismatch = true;
    }

    // Chapter match
    if (params.chapter && line.chapter) {
      if (line.chapter === params.chapter) score += 8;
      else mismatch = true;
    }

    // Seniority match
    if (params.seniority && line.seniority) {
      if (line.seniority === params.seniority) score += 4;
      else mismatch = true;
    }

    // Location match
    if (params.location && line.location) {
      if (line.location === params.location) score += 2;
      else mismatch = true;
    }

    // Work type match
    if (params.workType && line.workType) {
      if (line.workType === params.workType) score += 1;
      else mismatch = true;
    }

    return { line, score, mismatch };
  });

  // Filter out mismatched lines and sort by score descending
  const candidates = scored
    .filter((s) => !s.mismatch)
    .sort((a, b) => b.score - a.score);

  const best = candidates[0];
  if (!best) return null;

  return {
    costRateCents: best.line.costRateCents,
    billRateCents: best.line.billRateCents ?? 0,
    currency: best.line.rateCard.currency,
    rateCardId: best.line.rateCard.id,
    rateCardLineId: best.line.id,
    rateCardName: best.line.rateCard.name,
  };
}
