import crypto from "crypto";

function pad(value) {
  return String(value).padStart(2, "0");
}

function escapeText(value = "") {
  return String(value)
    .replace(/\\/g, "\\\\")
    .replace(/\n/g, "\\n")
    .replace(/,/g, "\\,")
    .replace(/;/g, "\\;");
}

function unescapeText(value = "") {
  return String(value)
    .replace(/\\n/g, "\n")
    .replace(/\\,/g, ",")
    .replace(/\\;/g, ";")
    .replace(/\\\\/g, "\\");
}

function foldLine(line) {
  if (line.length <= 73) return line;
  const parts = [];
  for (let i = 0; i < line.length; i += 73) {
    parts.push(i === 0 ? line.slice(i, i + 73) : ` ${line.slice(i, i + 73)}`);
  }
  return parts.join("\r\n");
}

function formatDateUtc(date) {
  const d = new Date(date);
  return `${d.getUTCFullYear()}${pad(d.getUTCMonth() + 1)}${pad(d.getUTCDate())}`;
}

function formatDateTimeUtc(date) {
  const d = new Date(date);
  return `${d.getUTCFullYear()}${pad(d.getUTCMonth() + 1)}${pad(d.getUTCDate())}T${pad(d.getUTCHours())}${pad(d.getUTCMinutes())}${pad(d.getUTCSeconds())}Z`;
}

export function buildIcsCalendar(events, { name = "BR-Office Kalender" } = {}) {
  const lines = [
    "BEGIN:VCALENDAR",
    "VERSION:2.0",
    "PRODID:-//BR-Office//Kalender//DE",
    "CALSCALE:GREGORIAN",
    "METHOD:PUBLISH",
    foldLine(`X-WR-CALNAME:${escapeText(name)}`),
  ];

  for (const event of events) {
    const uid = event.ical_uid || `${event.event_type || "calendar"}-${event.id || crypto.randomUUID()}@br-office.local`;
    const createdAt = event.created_at || event.updated_at || event.starts_at || new Date().toISOString();
    const updatedAt = event.updated_at || event.created_at || event.starts_at || new Date().toISOString();
    const descriptionParts = [];

    if (event.description) descriptionParts.push(event.description);
    if (event.reference) descriptionParts.push(`Referenz: ${event.reference}`);
    if (event.committee_name) descriptionParts.push(`Ausschuss: ${event.committee_name}`);
    if (event.primary_user_name) descriptionParts.push(`Verantwortlich: ${event.primary_user_name}`);

    lines.push("BEGIN:VEVENT");
    lines.push(`UID:${escapeText(uid)}`);
    lines.push(`DTSTAMP:${formatDateTimeUtc(updatedAt)}`);

    if (event.all_day) {
      lines.push(`DTSTART;VALUE=DATE:${formatDateUtc(event.starts_at)}`);
      const endSource = event.ends_at || event.starts_at;
      const endDate = new Date(endSource);
      endDate.setUTCDate(endDate.getUTCDate() + 1);
      lines.push(`DTEND;VALUE=DATE:${formatDateUtc(endDate)}`);
    } else {
      lines.push(`DTSTART:${formatDateTimeUtc(event.starts_at)}`);
      if (event.ends_at) lines.push(`DTEND:${formatDateTimeUtc(event.ends_at)}`);
    }

    lines.push(foldLine(`SUMMARY:${escapeText(event.title || "Termin")}`));
    if (event.location) lines.push(foldLine(`LOCATION:${escapeText(event.location)}`));
    if (descriptionParts.length) lines.push(foldLine(`DESCRIPTION:${escapeText(descriptionParts.join("\n"))}`));
    if (event.status) lines.push(`STATUS:${String(event.status).toUpperCase()}`);
    if (event.priority) lines.push(foldLine(`CATEGORIES:${escapeText(String(event.priority))}`));
    lines.push("END:VEVENT");
  }

  lines.push("END:VCALENDAR");
  return `${lines.join("\r\n")}\r\n`;
}

function parseLine(line) {
  const colonIndex = line.indexOf(":");
  if (colonIndex === -1) return null;
  const left = line.slice(0, colonIndex);
  const value = line.slice(colonIndex + 1);
  const [rawName, ...paramParts] = left.split(";");
  const params = {};

  for (const part of paramParts) {
    const [key, rawVal = ""] = part.split("=");
    params[key.toUpperCase()] = rawVal;
  }

  return {
    name: rawName.toUpperCase(),
    params,
    value,
  };
}

function parseDateValue(value, params = {}) {
  if (!value) return { iso: null, allDay: false };

  if (params.VALUE === "DATE" || /^\d{8}$/.test(value)) {
    const year = Number(value.slice(0, 4));
    const month = Number(value.slice(4, 6)) - 1;
    const day = Number(value.slice(6, 8));
    const d = new Date(Date.UTC(year, month, day, 0, 0, 0));
    return { iso: d.toISOString(), allDay: true };
  }

  const match = value.match(/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})?(Z)?$/);
  if (!match) return { iso: null, allDay: false };

  const [, y, mo, d, h, mi, s = "00", z] = match;
  if (z === "Z") {
    return {
      iso: new Date(Date.UTC(Number(y), Number(mo) - 1, Number(d), Number(h), Number(mi), Number(s))).toISOString(),
      allDay: false,
    };
  }

  return {
    iso: `${y}-${mo}-${d}T${h}:${mi}:${s}`,
    allDay: false,
  };
}

export function parseIcsCalendar(icsText) {
  const unfolded = String(icsText || "")
    .replace(/\r\n[ \t]/g, "")
    .replace(/\n[ \t]/g, "");

  const lines = unfolded.split(/\r?\n/).filter(Boolean);
  const events = [];
  let calendarName = "";
  let current = null;

  for (const rawLine of lines) {
    if (rawLine === "BEGIN:VEVENT") {
      current = {};
      continue;
    }
    if (rawLine === "END:VEVENT") {
      if (current) events.push(current);
      current = null;
      continue;
    }

    const parsed = parseLine(rawLine);
    if (!parsed) continue;

    if (!current && parsed.name === "X-WR-CALNAME") {
      calendarName = unescapeText(parsed.value);
      continue;
    }

    if (!current) continue;

    switch (parsed.name) {
      case "UID":
        current.uid = unescapeText(parsed.value);
        break;
      case "SUMMARY":
        current.title = unescapeText(parsed.value);
        break;
      case "DESCRIPTION":
        current.description = unescapeText(parsed.value);
        break;
      case "LOCATION":
        current.location = unescapeText(parsed.value);
        break;
      case "STATUS":
        current.status = unescapeText(parsed.value).toLowerCase();
        break;
      case "PRIORITY":
        current.priority = unescapeText(parsed.value);
        break;
      case "DTSTART": {
        const parsedDate = parseDateValue(parsed.value, parsed.params);
        current.starts_at = parsedDate.iso;
        if (parsedDate.allDay) current.all_day = true;
        break;
      }
      case "DTEND": {
        const parsedDate = parseDateValue(parsed.value, parsed.params);
        current.ends_at = parsedDate.iso;
        if (parsedDate.allDay) current.all_day = true;
        break;
      }
      default:
        break;
    }
  }

  return { calendarName, events };
}

function normalizePriority(priority) {
  const raw = String(priority ?? "").trim().toLowerCase();
  if (!raw) return "mittel";
  if (["1", "2", "3", "hoch", "high", "sehr_hoch", "urgent"].includes(raw)) return "hoch";
  if (["7", "8", "9", "niedrig", "low"].includes(raw)) return "niedrig";
  return "mittel";
}

function normalizeStatus(status) {
  const raw = String(status ?? "").trim().toLowerCase();
  if (!raw) return "geplant";
  if (["cancelled", "abgesagt", "canceled"].includes(raw)) return "abgesagt";
  if (["tentative", "vorbehaltlich"].includes(raw)) return "vorbehaltlich";
  if (["completed", "done", "erledigt"].includes(raw)) return "erledigt";
  return "geplant";
}

export function normalizeImportedEvent(rawEvent, defaults = {}) {
  const uidBase = rawEvent.uid || `${rawEvent.title || "Termin"}|${rawEvent.starts_at || ""}|${rawEvent.location || ""}`;
  return {
    source_uid: rawEvent.uid || crypto.createHash("sha1").update(uidBase).digest("hex"),
    title: rawEvent.title || "Importierter Termin",
    description: rawEvent.description || null,
    starts_at: rawEvent.starts_at,
    ends_at: rawEvent.ends_at || null,
    all_day: Boolean(rawEvent.all_day),
    location: rawEvent.location || null,
    status: normalizeStatus(rawEvent.status),
    priority: normalizePriority(rawEvent.priority),
    visibility: defaults.visibility || "intern",
    committee_id: defaults.committee_id ?? null,
    owner_user_id: defaults.owner_user_id ?? null,
    source_name: defaults.source_name || null,
    event_kind: defaults.event_kind || "imported",
    source_type: defaults.source_type || "ical",
  };
}
