// ==================== CUSTOMER REFERRAL SERVICE ====================
// "Geworben / angeworben": wer hat wen an Board geholt.

import prisma from '../lib/prisma.js';

// Erlaubte Beziehungsarten (Whitelist). Server vertraut dem Frontend-Dropdown
// nicht – ein handgebauter Request mit beliebigem String wird abgewiesen.
export const REFERRAL_RELATIONSHIPS = [
  'Ehepartner/in',
  'Lebenspartner/in',
  'Kind',
  'Enkelkind',
  'Onkel/Tante',
  'Neffe',
  'Freund/Kumpel',
  'Eltern',
  'Bruder/Schwester',
  'Schwiegertochter/Schwiegersohn',
  'Schwiegermutter/Schwiegervater',
  'Oma/Opa',
  'Uroma/Uropa',
  'Bekannte',
  'sonstige',
] as const;

const CUSTOMER_SELECT = {
  id: true,
  customerNumber: true,
  firstName: true,
  lastName: true,
  companyName: true,
  type: true,
} as const;

/**
 * Liefert für einen Kunden beide Richtungen:
 *  - recruitedBy: von wem dieser Kunde geworben wurde (max. 1)
 *  - recruited:   welche Kunden dieser Kunde geworben hat (beliebig viele)
 */
export async function getReferralsForCustomer(customerId: number) {
  const [recruitedBy, recruited] = await Promise.all([
    prisma.customerReferral.findUnique({
      where: { recruitedId: customerId },
      include: { recruiter: { select: CUSTOMER_SELECT } },
    }),
    prisma.customerReferral.findMany({
      where: { recruiterId: customerId },
      include: { recruited: { select: CUSTOMER_SELECT } },
      orderBy: { createdAt: 'asc' },
    }),
  ]);

  return {
    // Abschnitt 1: "<Kunde> wurde an Board geholt durch:"
    recruitedBy: recruitedBy
      ? { id: recruitedBy.id, relationship: recruitedBy.relationship, customer: recruitedBy.recruiter }
      : null,
    // Abschnitt 2: "<Kunde> hat folgende Kunden an Board geholt:"
    recruited: recruited.map((r) => ({
      id: r.id,
      relationship: r.relationship,
      customer: r.recruited,
    })),
  };
}

export class ReferralError extends Error {
  status: number;
  constructor(message: string, status = 400) {
    super(message);
    this.status = status;
  }
}

/**
 * Legt eine Werbe-Beziehung an: `recruiterId` hat `recruitedId` an Board geholt.
 */
export async function createReferral(params: {
  recruiterId: number;
  recruitedId: number;
  relationship: string;
  createdBy?: string;
}) {
  const { recruiterId, recruitedId, relationship, createdBy } = params;

  if (!Number.isInteger(recruiterId) || !Number.isInteger(recruitedId)) {
    throw new ReferralError('Ungültige Kunden-ID');
  }
  if (recruiterId === recruitedId) {
    throw new ReferralError('Ein Kunde kann sich nicht selbst werben');
  }
  if (!REFERRAL_RELATIONSHIPS.includes(relationship as typeof REFERRAL_RELATIONSHIPS[number])) {
    throw new ReferralError('Ungültige Beziehungsart');
  }

  // Beide Kunden müssen existieren
  const count = await prisma.customer.count({ where: { id: { in: [recruiterId, recruitedId] } } });
  if (count !== 2) {
    throw new ReferralError('Kunde nicht gefunden', 404);
  }

  // recruitedId ist @unique → höchstens ein Werber. Vorab prüfen für klare Meldung.
  const existing = await prisma.customerReferral.findUnique({ where: { recruitedId } });
  if (existing) {
    throw new ReferralError('Dieser Kunde wurde bereits als angeworben markiert. Bitte zuerst den bestehenden Eintrag entfernen.', 409);
  }

  const created = await prisma.customerReferral.create({
    data: { recruiterId, recruitedId, relationship, createdBy },
    include: { recruiter: { select: CUSTOMER_SELECT }, recruited: { select: CUSTOMER_SELECT } },
  });
  return created;
}

/**
 * Ändert eine bestehende Werbe-Beziehung (Beziehungsart und/oder den
 * beteiligten Gegen-Kunden). recruiter/recruited werden vom Controller aus
 * der Richtung + aktueller Kundenakte bestimmt.
 */
export async function updateReferral(params: {
  id: number;
  recruiterId: number;
  recruitedId: number;
  relationship: string;
}) {
  const { id, recruiterId, recruitedId, relationship } = params;

  if (!Number.isInteger(id)) {
    throw new ReferralError('Ungültige ID');
  }
  if (!Number.isInteger(recruiterId) || !Number.isInteger(recruitedId)) {
    throw new ReferralError('Ungültige Kunden-ID');
  }
  if (recruiterId === recruitedId) {
    throw new ReferralError('Ein Kunde kann sich nicht selbst werben');
  }
  if (!REFERRAL_RELATIONSHIPS.includes(relationship as typeof REFERRAL_RELATIONSHIPS[number])) {
    throw new ReferralError('Ungültige Beziehungsart');
  }

  const existing = await prisma.customerReferral.findUnique({ where: { id } });
  if (!existing) {
    throw new ReferralError('Eintrag nicht gefunden', 404);
  }

  // Beide Kunden müssen existieren
  const count = await prisma.customer.count({ where: { id: { in: [recruiterId, recruitedId] } } });
  if (count !== 2) {
    throw new ReferralError('Kunde nicht gefunden', 404);
  }

  // recruitedId ist @unique → falls der Geworbene auf einen anderen Kunden
  // geändert wird, der bereits einen Werber hat, klare Meldung statt DB-Fehler.
  if (recruitedId !== existing.recruitedId) {
    const clash = await prisma.customerReferral.findUnique({ where: { recruitedId } });
    if (clash && clash.id !== id) {
      throw new ReferralError('Dieser Kunde wurde bereits als angeworben markiert. Bitte zuerst den bestehenden Eintrag entfernen.', 409);
    }
  }

  const updated = await prisma.customerReferral.update({
    where: { id },
    data: { recruiterId, recruitedId, relationship },
    include: { recruiter: { select: CUSTOMER_SELECT }, recruited: { select: CUSTOMER_SELECT } },
  });
  return updated;
}

export async function deleteReferral(id: number): Promise<boolean> {
  if (!Number.isInteger(id)) return false;
  const existing = await prisma.customerReferral.findUnique({ where: { id } });
  if (!existing) return false;
  await prisma.customerReferral.delete({ where: { id } });
  return true;
}

/**
 * Kundensuche für die Werber-Auswahl. Breit über die wichtigsten
 * Kundenakten-Felder, schließt den eigenen Kunden aus.
 */
export async function searchCustomersForReferral(search: string, excludeCustomerId: number) {
  return prisma.customer.findMany({
    where: {
      id: { not: excludeCustomerId },
      OR: [
        { firstName: { contains: search } },
        { lastName: { contains: search } },
        { companyName: { contains: search } },
        { customerNumber: { contains: search } },
        { email: { contains: search } },
        { phone: { contains: search } },
        { mobile: { contains: search } },
      ],
    },
    select: CUSTOMER_SELECT,
    take: 10,
  });
}
