import nodemailer from "nodemailer";

import { env } from "../../config/env.js";
import { HttpError } from "../../lib/http-error.js";
import { query, queryOne } from "../../lib/db.js";
import { getInspectionEmailSettings } from "./settings.service.js";

const getPublicAssetUrl = (path: string) => {
  const baseUrl = (env.APP_BASE_URL || "https://track.visau.duckdns.org").replace(/\/+$/, "");
  return `${baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
};

const renderMailShell = (contentHtml: string) => {
  const logoUrl = getPublicAssetUrl("/VISAU-LOGO.png");

  return `
    <div style="font-family:Arial,sans-serif;background:#0b1220;color:#e8eefc;padding:24px">
      <div style="max-width:560px;margin:0 auto;border:1px solid rgba(88,255,125,.35);border-radius:18px;padding:24px;background:#121b2b">
        <div style="display:flex;align-items:flex-start;justify-content:space-between;gap:24px">
          <div style="min-width:0;flex:1 1 auto">
            ${contentHtml}
          </div>
          <div style="flex:0 0 auto;padding-top:4px;text-align:center">
            <img src="${logoUrl}" alt="VISAU" style="display:block;width:132px;max-width:132px;height:auto;margin:0 auto" />
            <div style="margin-top:8px;font-size:11px;letter-spacing:.28em;text-transform:uppercase;color:#78caff;font-weight:700;white-space:nowrap">AUTOTRACKING</div>
          </div>
        </div>
      </div>
    </div>
  `;
};

const getTransporter = () => {
  if (!env.SMTP_HOST || !env.SMTP_USER || !env.SMTP_PASSWORD) {
    throw new HttpError(500, "SMTP nie jest skonfigurowane");
  }

  return nodemailer.createTransport({
    host: env.SMTP_HOST,
    port: env.SMTP_PORT,
    secure: env.SMTP_SECURE,
    auth: {
      user: env.SMTP_USER,
      pass: env.SMTP_PASSWORD,
    },
  });
};

export const sendTrackingTestEmail = async () => {
  const transporter = getTransporter();
  const from = env.SMTP_FROM ?? env.SMTP_USER!;
  const sentAt = new Date().toLocaleString("pl-PL", {
    dateStyle: "short",
    timeStyle: "medium",
  });
  const inspectionSettings = await getInspectionEmailSettings();
  const recipients = inspectionSettings.recipients.length > 0
    ? inspectionSettings.recipients
    : [env.TEST_MAIL_RECIPIENT];

  const result = await transporter.sendMail({
    from: `"VISAU AUTOTRACKING" <${from}>`,
    to: recipients,
    subject: "VISAU TRACKING: test wysyłki maila",
    text: [
      "To jest testowy mail z panelu VISAU TRACKING.",
      "",
      `Odbiorcy: ${recipients.join(", ")}`,
      `Czas wysyłki: ${sentAt}`,
      "Jeśli dostałeś tę wiadomość, konfiguracja SMTP działa poprawnie.",
    ].join("\n"),
    html: renderMailShell(`
      <div style="font-size:13px;letter-spacing:.22em;text-transform:uppercase;color:#78caff;margin-bottom:10px">VISAU AUTOTRACKING</div>
      <div style="font-size:24px;font-weight:700;color:#ffffff;margin-bottom:14px">Test wysyłki maila</div>
      <div style="font-size:15px;line-height:1.6;color:#c9d6ef">
        To jest testowy mail z panelu <strong>VISAU TRACKING</strong>.<br />
        Odbiorcy: <strong>${recipients.join(", ")}</strong><br />
        Czas wysyłki: <strong>${sentAt}</strong><br />
        Jeśli dostałeś tę wiadomość, konfiguracja SMTP działa poprawnie.
      </div>
    `),
  });

  return {
    accepted: result.accepted,
    rejected: result.rejected,
    messageId: result.messageId,
  };
};

const normalizeInspectionDate = (value?: string | Date | number | null) => {
  if (!value) {
    return null;
  }

  if (value instanceof Date) {
    if (Number.isNaN(value.getTime())) {
      return null;
    }

    return value.toISOString().slice(0, 10);
  }

  const trimmed = String(value).trim();
  if (!trimmed) {
    return null;
  }

  const dateOnlyMatch = trimmed.match(/^(\d{4}-\d{2}-\d{2})/);
  if (dateOnlyMatch) {
    return dateOnlyMatch[1] ?? null;
  }

  const parsed = new Date(trimmed);
  if (Number.isNaN(parsed.getTime())) {
    return null;
  }

  return parsed.toISOString().slice(0, 10);
};

const getDayDiff = (normalizedInspectionDate: string) => {
  const today = new Date();
  const todayUtc = Date.UTC(today.getFullYear(), today.getMonth(), today.getDate());
  const due = new Date(`${normalizedInspectionDate}T00:00:00`);
  const dueUtc = Date.UTC(due.getFullYear(), due.getMonth(), due.getDate());

  if (Number.isNaN(dueUtc)) {
    return null;
  }

  return Math.floor((dueUtc - todayUtc) / 86400000);
};

const SERVICE_ALERT_RECIPIENT = "pr@sterion.pl";

const serviceAlertCopy = {
  inspection: {
    notificationType: "inspection-due-soon-pr-sterion",
    title: "Przegląd techniczny",
    subject: "przegląd techniczny",
  },
  oil: {
    notificationType: "oil-change-due-soon",
    title: "Wymiana oleju",
    subject: "wymiana oleju",
  },
  tires: {
    notificationType: "tire-change-due-soon",
    title: "Wymiana opon",
    subject: "wymiana opon",
  },
} as const;

export const sendServiceDueSoonEmailIfNeeded = async (input: {
  vehicleId: string;
  vehicleName: string;
  plateNumber?: string | null;
  dueDate?: string | null;
  serviceType: keyof typeof serviceAlertCopy;
}) => {
  const normalizedDueDate = normalizeInspectionDate(input.dueDate);
  if (!normalizedDueDate) {
    return;
  }

  const dayDiff = getDayDiff(normalizedDueDate);
  if (dayDiff == null || dayDiff > 14) {
    return;
  }

  const copy = serviceAlertCopy[input.serviceType];
  const inserted = await queryOne<{ vehicle_id: string }>(
    `
      insert into vehicle_inspection_email_events (
        vehicle_id,
        inspection_due_date,
        notification_type,
        recipients,
        sent_at
      )
      values ($1, $2::date, $3, $4::text[], now())
      on conflict (vehicle_id, inspection_due_date, notification_type) do nothing
      returning vehicle_id
    `,
    [input.vehicleId, normalizedDueDate, copy.notificationType, [SERVICE_ALERT_RECIPIENT]],
  );

  if (!inserted) {
    return;
  }

  const transporter = getTransporter();
  const from = env.SMTP_FROM ?? env.SMTP_USER!;
  const dueDateLabel = new Date(`${normalizedDueDate}T00:00:00`).toLocaleDateString("pl-PL");
  const daysLabel = dayDiff <= 0
    ? `Termin: ${copy.subject} już minął.`
    : `Do terminu zostało ${dayDiff} dni.`;
  const vehicleLabel = input.plateNumber?.trim()
    ? `${input.vehicleName} (${input.plateNumber.trim()})`
    : input.vehicleName;

  try {
    await transporter.sendMail({
      from: `"VISAU AUTOTRACKING" <${from}>`,
      to: SERVICE_ALERT_RECIPIENT,
      subject: `VISAU TRACKING: ${copy.subject} - ${vehicleLabel}`,
      text: [
        `Pojazd: ${vehicleLabel}`,
        `${copy.title}: ${dueDateLabel}`,
        daysLabel,
        "",
        `Pojazd wszedł w próg 14 dni: ${copy.subject}.`,
      ].join("\n"),
      html: renderMailShell(`
        <div style="font-size:13px;letter-spacing:.22em;text-transform:uppercase;color:#78caff;margin-bottom:10px">VISAU AUTOTRACKING</div>
        <div style="font-size:24px;font-weight:700;color:#ffffff;margin-bottom:14px">${copy.title}</div>
        <div style="font-size:15px;line-height:1.6;color:#c9d6ef">
          Pojazd: <strong>${vehicleLabel}</strong><br />
          Termin: <strong>${dueDateLabel}</strong><br />
          ${daysLabel}
        </div>
      `),
    });
  } catch (error) {
    await query(
      `
        delete from vehicle_inspection_email_events
        where vehicle_id = $1
          and inspection_due_date = $2::date
          and notification_type = $3
      `,
      [input.vehicleId, normalizedDueDate, copy.notificationType],
    );

    throw error;
  }
};

export const sendInspectionDueSoonEmailIfNeeded = async (input: {
  vehicleId: string;
  vehicleName: string;
  plateNumber?: string | null;
  inspectionDueDate?: string | null;
}) => {
  const normalizedInspectionDate = normalizeInspectionDate(input.inspectionDueDate);
  if (!normalizedInspectionDate) {
    return;
  }

  const dayDiff = getDayDiff(normalizedInspectionDate);
  if (dayDiff == null || dayDiff > 14) {
    return;
  }

  const settings = await getInspectionEmailSettings();
  const recipients = settings.recipients;
  if (recipients.length === 0) {
    return;
  }

  const inserted = await queryOne<{ vehicle_id: string }>(
    `
      insert into vehicle_inspection_email_events (
        vehicle_id,
        inspection_due_date,
        notification_type,
        recipients,
        sent_at
      )
      values ($1, $2::date, 'inspection-due-soon', $3::text[], now())
      on conflict (vehicle_id, inspection_due_date, notification_type) do nothing
      returning vehicle_id
    `,
    [input.vehicleId, normalizedInspectionDate, recipients],
  );

  if (!inserted) {
    return;
  }

  const transporter = getTransporter();
  const from = env.SMTP_FROM ?? env.SMTP_USER!;
  const dueDateLabel = new Date(`${normalizedInspectionDate}T00:00:00`).toLocaleDateString("pl-PL");
  const daysLabel = dayDiff <= 0 ? "Termin przeglądu już minął." : `Do terminu przeglądu zostało ${dayDiff} dni.`;
  const vehicleLabel = input.plateNumber?.trim()
    ? `${input.vehicleName} (${input.plateNumber.trim()})`
    : input.vehicleName;

  try {
    await transporter.sendMail({
      from: `"VISAU AUTOTRACKING" <${from}>`,
      to: recipients.join(", "),
      subject: `VISAU TRACKING: przegląd pojazdu ${vehicleLabel}`,
      text: [
        `Pojazd: ${vehicleLabel}`,
        `Termin przeglądu: ${dueDateLabel}`,
        daysLabel,
        "",
        "Pojazd wszedł w próg 14 dni do terminu przeglądu.",
      ].join("\n"),
      html: renderMailShell(`
        <div style="font-size:13px;letter-spacing:.22em;text-transform:uppercase;color:#78caff;margin-bottom:10px">VISAU AUTOTRACKING</div>
        <div style="font-size:24px;font-weight:700;color:#ffffff;margin-bottom:14px">Przegląd pojazdu</div>
        <div style="font-size:15px;line-height:1.6;color:#c9d6ef">
          Pojazd: <strong>${vehicleLabel}</strong><br />
          Termin przeglądu: <strong>${dueDateLabel}</strong><br />
          ${daysLabel}
        </div>
      `),
    });
  } catch (error) {
    await query(
      `
        delete from vehicle_inspection_email_events
        where vehicle_id = $1
          and inspection_due_date = $2::date
          and notification_type = 'inspection-due-soon'
      `,
      [input.vehicleId, normalizedInspectionDate],
    );

    throw error;
  }
};
