// ============================================================
// Mapping-Funktionen: Lexware Office <-> CRM
// ============================================================

import { VoucherType } from '.prisma/crm-client';
import {
  LexwareContact,
  LexwareVoucherDetail,
  LexwareVoucherListItem,
} from '../interfaces/lexware-api.interfaces';

// --------------------------------------------------------
// Typen fuer Multi-Value Email/Phone Arrays
// --------------------------------------------------------
interface EmailEntry {
  email: string;
  type: 'WORK' | 'PERSONAL' | 'OTHER';
  isPrimary: boolean;
}

interface PhoneEntry {
  phone: string;
  type: 'OFFICE' | 'MOBILE' | 'FAX';
  isPrimary: boolean;
}

// --------------------------------------------------------
// Lexware Contact -> CRM Company
// --------------------------------------------------------
export function lexwareContactToCompanyData(lc: LexwareContact): {
  name: string;
  email?: string;
  phone?: string;
  website?: string;
  street?: string;
  zip?: string;
  city?: string;
  country?: string;
  notes?: string;
  emails: EmailEntry[];
  phones: PhoneEntry[];
} {
  const name =
    lc.company?.name || [lc.person?.firstName, lc.person?.lastName].filter(Boolean).join(' ') || 'Unbekannt';

  const billingAddr = lc.addresses?.billing?.[0];
  const email = getFirstEmail(lc);
  const phone = getFirstPhone(lc);

  return {
    name,
    email: email || undefined,
    phone: phone || undefined,
    street: billingAddr?.street || undefined,
    zip: billingAddr?.zip || undefined,
    city: billingAddr?.city || undefined,
    country: billingAddr?.countryCode || 'DE',
    notes: lc.note || undefined,
    emails: extractAllEmails(lc),
    phones: extractAllPhones(lc),
  };
}

// --------------------------------------------------------
// Lexware Contact -> CRM Contact
// --------------------------------------------------------
export function lexwareContactToContactData(lc: LexwareContact): {
  firstName?: string;
  lastName?: string;
  companyName?: string;
  position?: string;
  email?: string;
  phone?: string;
  mobile?: string;
  street?: string;
  zip?: string;
  city?: string;
  country?: string;
  notes?: string;
  type: 'PERSON' | 'ORGANIZATION';
  emails: EmailEntry[];
  phones: PhoneEntry[];
} {
  const isPerson = !!lc.person;
  const billingAddr = lc.addresses?.billing?.[0];
  const email = getFirstEmail(lc);
  const phone = getFirstPhone(lc);
  const mobile = lc.phoneNumbers?.mobile?.[0];
  const emails = extractAllEmails(lc);
  const phones = extractAllPhones(lc);

  if (isPerson) {
    return {
      type: 'PERSON',
      firstName: lc.person?.firstName || undefined,
      lastName: lc.person?.lastName || 'Unbekannt',
      companyName: lc.company?.name || undefined,
      position: lc.company?.contactPersons?.[0]?.primary
        ? 'Primaerkontakt'
        : undefined,
      email: email || undefined,
      phone: phone || undefined,
      mobile: mobile || undefined,
      street: billingAddr?.street || undefined,
      zip: billingAddr?.zip || undefined,
      city: billingAddr?.city || undefined,
      country: billingAddr?.countryCode || 'DE',
      notes: lc.note || undefined,
      emails,
      phones,
    };
  }

  return {
    type: 'ORGANIZATION',
    firstName: lc.company?.contactPersons?.[0]?.firstName || undefined,
    lastName:
      lc.company?.contactPersons?.[0]?.lastName || lc.company?.name || 'Unbekannt',
    companyName: lc.company?.name || undefined,
    email: email || undefined,
    phone: phone || undefined,
    mobile: mobile || undefined,
    street: billingAddr?.street || undefined,
    zip: billingAddr?.zip || undefined,
    city: billingAddr?.city || undefined,
    country: billingAddr?.countryCode || 'DE',
    notes: lc.note || undefined,
    emails,
    phones,
  };
}

// --------------------------------------------------------
// CRM Company -> Lexware Contact Body (fuer POST/PUT)
// --------------------------------------------------------
export function companyToLexwareContactBody(company: {
  name: string;
  email?: string | null;
  phone?: string | null;
  street?: string | null;
  zip?: string | null;
  city?: string | null;
  country?: string | null;
  notes?: string | null;
  emails?: Array<{ email: string; type: string }>;
  phones?: Array<{ phone: string; type: string }>;
}): Record<string, unknown> {
  const body: Record<string, unknown> = {
    version: 0,
    roles: { customer: {} },
    company: { name: company.name },
  };

  if (company.street || company.zip || company.city) {
    body.addresses = {
      billing: [
        {
          street: company.street || undefined,
          zip: company.zip || undefined,
          city: company.city || undefined,
          countryCode: company.country || 'DE',
        },
      ],
    };
  }

  // Multi-Value emails → Lexware categories
  if (company.emails && company.emails.length > 0) {
    const emailAddresses: Record<string, string[]> = {};
    for (const e of company.emails) {
      const category = emailTypeToLexwareCategory(e.type);
      if (!emailAddresses[category]) emailAddresses[category] = [];
      emailAddresses[category].push(e.email);
    }
    body.emailAddresses = emailAddresses;
  } else if (company.email) {
    body.emailAddresses = { business: [company.email] };
  }

  // Multi-Value phones → Lexware categories
  if (company.phones && company.phones.length > 0) {
    const phoneNumbers: Record<string, string[]> = {};
    for (const p of company.phones) {
      const category = phoneTypeToLexwareCategory(p.type);
      if (!phoneNumbers[category]) phoneNumbers[category] = [];
      phoneNumbers[category].push(p.phone);
    }
    body.phoneNumbers = phoneNumbers;
  } else if (company.phone) {
    body.phoneNumbers = { business: [company.phone] };
  }

  if (company.notes) {
    body.note = company.notes.substring(0, 1000);
  }

  return body;
}

// --------------------------------------------------------
// CRM Contact -> Lexware Contact Body (fuer POST/PUT)
// --------------------------------------------------------
export function contactToLexwareContactBody(contact: {
  firstName?: string | null;
  lastName?: string | null;
  companyName?: string | null;
  email?: string | null;
  phone?: string | null;
  mobile?: string | null;
  street?: string | null;
  zip?: string | null;
  city?: string | null;
  country?: string | null;
  notes?: string | null;
  type: string;
  emails?: Array<{ email: string; type: string }>;
  phones?: Array<{ phone: string; type: string }>;
}): Record<string, unknown> {
  const body: Record<string, unknown> = {
    version: 0,
    roles: { customer: {} },
  };

  if (contact.type === 'ORGANIZATION' && contact.companyName) {
    body.company = { name: contact.companyName };
  } else {
    body.person = {
      firstName: contact.firstName || undefined,
      lastName: contact.lastName || 'Unbekannt',
    };
  }

  if (contact.street || contact.zip || contact.city) {
    body.addresses = {
      billing: [
        {
          street: contact.street || undefined,
          zip: contact.zip || undefined,
          city: contact.city || undefined,
          countryCode: contact.country || 'DE',
        },
      ],
    };
  }

  // Multi-Value emails → Lexware categories
  if (contact.emails && contact.emails.length > 0) {
    const emailAddresses: Record<string, string[]> = {};
    for (const e of contact.emails) {
      const category = emailTypeToLexwareCategory(e.type);
      if (!emailAddresses[category]) emailAddresses[category] = [];
      emailAddresses[category].push(e.email);
    }
    body.emailAddresses = emailAddresses;
  } else if (contact.email) {
    body.emailAddresses = { business: [contact.email] };
  }

  // Multi-Value phones → Lexware categories
  if (contact.phones && contact.phones.length > 0) {
    const phoneNumbers: Record<string, string[]> = {};
    for (const p of contact.phones) {
      const category = phoneTypeToLexwareCategory(p.type);
      if (!phoneNumbers[category]) phoneNumbers[category] = [];
      phoneNumbers[category].push(p.phone);
    }
    body.phoneNumbers = phoneNumbers;
  } else {
    const phoneNumbers: Record<string, string[]> = {};
    if (contact.phone) phoneNumbers.business = [contact.phone];
    if (contact.mobile) phoneNumbers.mobile = [contact.mobile];
    if (Object.keys(phoneNumbers).length > 0) {
      body.phoneNumbers = phoneNumbers;
    }
  }

  if (contact.notes) {
    body.note = contact.notes.substring(0, 1000);
  }

  return body;
}

// --------------------------------------------------------
// Voucher Type Mapping
// --------------------------------------------------------
export function voucherTypeFromLexware(lexwareType: string): VoucherType {
  const map: Record<string, VoucherType> = {
    invoice: 'INVOICE',
    quotation: 'QUOTATION',
    orderconfirmation: 'ORDER_CONFIRMATION',
    creditnote: 'CREDIT_NOTE',
  };
  return map[lexwareType.toLowerCase()] || 'INVOICE';
}

export function voucherTypeToLexwareEndpoint(type: VoucherType): string {
  const map: Record<VoucherType, string> = {
    INVOICE: 'invoices',
    QUOTATION: 'quotations',
    ORDER_CONFIRMATION: 'order-confirmations',
    CREDIT_NOTE: 'credit-notes',
  };
  return map[type];
}

// --------------------------------------------------------
// Deep Link Builder
// --------------------------------------------------------
export function buildLexwareDeepLink(
  voucherType: VoucherType,
  voucherId: string,
): string {
  const typeMap: Record<VoucherType, string> = {
    INVOICE: 'invoices',
    QUOTATION: 'quotations',
    ORDER_CONFIRMATION: 'order-confirmations',
    CREDIT_NOTE: 'credit-notes',
  };
  const typePath = typeMap[voucherType];
  return `https://app.lexware.de/permalink/${typePath}/view/${voucherId}`;
}

// --------------------------------------------------------
// Lexware Voucher Detail -> CRM Cache Daten
// --------------------------------------------------------
export function voucherDetailToCacheData(
  detail: LexwareVoucherDetail,
  voucherType: VoucherType,
  lexwareContactId: string,
): {
  voucherType: VoucherType;
  voucherNumber: string | null;
  voucherDate: Date | null;
  voucherStatus: string | null;
  totalGrossAmount: number | null;
  totalNetAmount: number | null;
  totalTaxAmount: number | null;
  currency: string;
  title: string | null;
  lineItemsCount: number | null;
  lineItemsJson: string | null;
  lexwareContactId: string;
  lexwareDeepLink: string;
} {
  const lineItems = detail.lineItems?.map((li) => ({
    name: li.name,
    quantity: li.quantity,
    unitName: li.unitName,
    unitPrice: li.unitPrice?.grossAmount,
    amount: li.lineItemAmount,
  }));

  return {
    voucherType,
    voucherNumber: detail.voucherNumber || null,
    voucherDate: detail.voucherDate ? new Date(detail.voucherDate) : null,
    voucherStatus: detail.voucherStatus || null,
    totalGrossAmount: detail.totalPrice?.totalGrossAmount ?? null,
    totalNetAmount: detail.totalPrice?.totalNetAmount ?? null,
    totalTaxAmount: detail.totalPrice?.totalTaxAmount ?? null,
    currency: detail.totalPrice?.currency || 'EUR',
    title: detail.title || null,
    lineItemsCount: detail.lineItems?.length ?? null,
    lineItemsJson: lineItems ? JSON.stringify(lineItems) : null,
    lexwareContactId,
    lexwareDeepLink: buildLexwareDeepLink(voucherType, detail.id),
  };
}

// --------------------------------------------------------
// Hilfsfunktionen
// --------------------------------------------------------
function getFirstEmail(lc: LexwareContact): string | undefined {
  const emails = lc.emailAddresses;
  if (!emails) return undefined;
  return (
    emails.business?.[0] ||
    emails.office?.[0] ||
    emails.private?.[0] ||
    emails.other?.[0]
  );
}

function getFirstPhone(lc: LexwareContact): string | undefined {
  const phones = lc.phoneNumbers;
  if (!phones) return undefined;
  return (
    phones.business?.[0] ||
    phones.office?.[0] ||
    phones.private?.[0] ||
    phones.other?.[0]
  );
}

/**
 * Alle Lexware-Emails in Multi-Value Array konvertieren.
 * Mapping: business/office → WORK, private → PERSONAL, other → OTHER
 */
function extractAllEmails(lc: LexwareContact): EmailEntry[] {
  const result: EmailEntry[] = [];
  const emails = lc.emailAddresses;
  if (!emails) return result;

  let isFirst = true;
  const addEmails = (addresses: string[] | undefined, type: EmailEntry['type']) => {
    if (!addresses) return;
    for (const addr of addresses) {
      result.push({ email: addr, type, isPrimary: isFirst });
      isFirst = false;
    }
  };

  addEmails(emails.business, 'WORK');
  addEmails(emails.office, 'WORK');
  addEmails(emails.private, 'PERSONAL');
  addEmails(emails.other, 'OTHER');

  return result;
}

/**
 * Alle Lexware-Phones in Multi-Value Array konvertieren.
 * Mapping: business/office → OFFICE, mobile → MOBILE, fax → FAX, private/other → OFFICE
 */
function extractAllPhones(lc: LexwareContact): PhoneEntry[] {
  const result: PhoneEntry[] = [];
  const phones = lc.phoneNumbers;
  if (!phones) return result;

  let isFirst = true;
  const addPhones = (numbers: string[] | undefined, type: PhoneEntry['type']) => {
    if (!numbers) return;
    for (const num of numbers) {
      result.push({ phone: num, type, isPrimary: isFirst });
      isFirst = false;
    }
  };

  addPhones(phones.business, 'OFFICE');
  addPhones(phones.office, 'OFFICE');
  addPhones(phones.mobile, 'MOBILE');
  addPhones(phones.fax, 'FAX');
  addPhones(phones.private, 'OFFICE');
  addPhones(phones.other, 'OFFICE');

  return result;
}

/**
 * CRM EmailType → Lexware Kategorie
 */
function emailTypeToLexwareCategory(type: string): string {
  switch (type) {
    case 'WORK': return 'business';
    case 'PERSONAL': return 'private';
    case 'OTHER': return 'other';
    default: return 'business';
  }
}

/**
 * CRM PhoneType → Lexware Kategorie
 */
function phoneTypeToLexwareCategory(type: string): string {
  switch (type) {
    case 'OFFICE': return 'business';
    case 'MOBILE': return 'mobile';
    case 'FAX': return 'fax';
    default: return 'business';
  }
}

// --------------------------------------------------------
// Lexware VoucherList Item -> Voucher Type
// --------------------------------------------------------
export function voucherListItemToType(
  item: LexwareVoucherListItem,
): VoucherType {
  return voucherTypeFromLexware(item.voucherType);
}
