/**
 * موتور مسیریابی گزارش‌های مردمی.
 *
 * قواعد از جدول routing_rules خوانده می‌شوند (کاملاً از پنل مدیریت قابل تنظیم).
 * هر قاعده مجموعه‌ای از شرط‌های اختیاری دارد که با AND ارزیابی می‌شوند؛ قاعده‌ای
 * که بیشترین شرط منطبق و بالاترین اولویت را داشته باشد برنده است.
 * اگر هیچ قاعده‌ای منطبق نشود، گزارش به صف «مسیریابی دستی» می‌رود — هرگز به‌صورت
 * تصادفی به سازمانی ارجاع داده نمی‌شود.
 */
import { and, eq, isNull, or } from 'drizzle-orm';
import { getDb } from '../../database/client.js';
import { routingRules, departments, organizations, regions } from '../../database/schema/index.js';
import { normalizePersian } from '../../common/persian.js';

export type RoutableReport = {
  categoryKey: string;
  kind: string;
  severity: string;
  regionId: string | null;
  title: string;
  body: string;
  targetOrganizationId?: string | null;
};

export type RoutingDecision = {
  matched: boolean;
  ruleId: string | null;
  ruleName: string | null;
  organizationId: string | null;
  departmentId: string | null;
  guildId: string | null;
  priority: string;
  explanation: string;
};

/** والدهای یک منطقه (برای تطبیق قاعده‌ی سطح استان با گزارش سطح محله) */
async function regionChain(regionId: string | null): Promise<string[]> {
  if (!regionId) return [];
  const db = getDb();
  const chain: string[] = [];
  let current: string | null = regionId;
  for (let i = 0; i < 6 && current; i++) {
    chain.push(current);
    const [row] = await db.select({ parentId: regions.parentId }).from(regions).where(eq(regions.id, current));
    current = row?.parentId ?? null;
  }
  return chain;
}

export async function routeReport(report: RoutableReport): Promise<RoutingDecision> {
  const db = getDb();

  // اگر شهروند صراحتاً سازمان مقصد را انتخاب کرده باشد، انتخاب او محترم است
  if (report.targetOrganizationId) {
    const [org] = await db.select().from(organizations).where(eq(organizations.id, report.targetOrganizationId));
    if (org) {
      const dept = await pickDepartment(org.id, report.regionId);
      return {
        matched: true, ruleId: null, ruleName: 'انتخاب مستقیم گزارش‌دهنده',
        organizationId: org.id, departmentId: dept, guildId: null,
        priority: report.severity,
        explanation: `گزارش‌دهنده سازمان «${org.nameFa}» را به‌عنوان مقصد انتخاب کرده است.`,
      };
    }
  }

  const rules = await db.select().from(routingRules).where(eq(routingRules.isActive, true));
  const chain = await regionChain(report.regionId);
  const haystack = normalizePersian(`${report.title} ${report.body}`);

  let best: { rule: typeof rules[number]; score: number; reasons: string[] } | null = null;

  for (const rule of rules) {
    let score = 0;
    const reasons: string[] = [];

    if (rule.matchCategoryKey) {
      if (rule.matchCategoryKey !== report.categoryKey) continue;
      score += 40; reasons.push(`دسته «${rule.matchCategoryKey}»`);
    }
    if (rule.matchKind) {
      if (rule.matchKind !== report.kind) continue;
      score += 10; reasons.push(`نوع «${rule.matchKind}»`);
    }
    if (rule.matchSeverity) {
      if (rule.matchSeverity !== report.severity) continue;
      score += 10; reasons.push(`شدت «${rule.matchSeverity}»`);
    }
    if (rule.matchRegionId) {
      if (!chain.includes(rule.matchRegionId)) continue;
      score += 30; reasons.push('انطباق منطقه جغرافیایی');
    }
    const keywords = rule.matchKeywords ?? [];
    if (keywords.length) {
      const hits = keywords.filter((k) => haystack.includes(normalizePersian(k)));
      if (hits.length === 0) continue;
      score += 15 * hits.length; reasons.push(`کلیدواژه‌های ${hits.join('، ')}`);
    }
    if (score === 0) continue;

    // اولویت عددی کمتر یعنی مهم‌تر
    score += Math.max(0, 100 - rule.priority) / 10;
    if (!best || score > best.score) best = { rule, score, reasons };
  }

  if (!best) {
    return {
      matched: false, ruleId: null, ruleName: null, organizationId: null, departmentId: null,
      guildId: null, priority: report.severity,
      explanation: 'هیچ قاعده مسیریابی منطبقی یافت نشد؛ گزارش برای ارجاع دستی در صف ناظران قرار گرفت.',
    };
  }

  const departmentId = best.rule.targetDepartmentId
    ?? (best.rule.targetOrganizationId ? await pickDepartment(best.rule.targetOrganizationId, report.regionId) : null);

  return {
    matched: true,
    ruleId: best.rule.id,
    ruleName: best.rule.nameFa,
    organizationId: best.rule.targetOrganizationId,
    departmentId,
    guildId: best.rule.targetGuildId,
    priority: best.rule.setPriority ?? report.severity,
    explanation: `قاعده «${best.rule.nameFa}» بر اساس ${best.reasons.join(' و ')} اعمال شد.`,
  };
}

/** انتخاب اداره‌ی متناسب با منطقه‌ی گزارش در داخل سازمان مقصد */
async function pickDepartment(organizationId: string, regionId: string | null): Promise<string | null> {
  const db = getDb();
  const chain = await regionChain(regionId);
  const rows = await db.select().from(departments).where(eq(departments.organizationId, organizationId));
  if (rows.length === 0) return null;
  for (const region of chain) {
    const match = rows.find((d) => d.regionId === region);
    if (match) return match.id;
  }
  return rows.find((d) => !d.regionId)?.id ?? rows[0].id;
}

/** پیش‌نمایش تصمیم مسیریابی برای پنل مدیریت (بدون اعمال) */
export async function previewRouting(report: RoutableReport) {
  return routeReport(report);
}

/** قواعد بدون مقصد معتبر — برای هشدار در پنل مدیریت */
export async function invalidRules() {
  const db = getDb();
  return db
    .select()
    .from(routingRules)
    .where(and(eq(routingRules.isActive, true), or(isNull(routingRules.targetOrganizationId), isNull(routingRules.targetOrganizationId))));
}
