const BIRTHDAY_COLOR = '#E11D48';
const BIRTHDAY_RRULE = 'FREQ=YEARLY;INTERVAL=1';

function pad2(n) {
  return String(n).padStart(2, '0');
}

function leapYear(year) {
  return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
}

function normalizedMonthDay(birthDate, year) {
  const [, monthStr, dayStr] = String(birthDate).split('-');
  const month = parseInt(monthStr, 10);
  let day = parseInt(dayStr, 10);
  if (month === 2 && day === 29 && !leapYear(year)) day = 28;
  return `${year}-${pad2(month)}-${pad2(day)}`;
}

function nextBirthdayDate(birthDate, from = new Date()) {
  const now = from instanceof Date ? from : new Date(from);
  const thisYear = normalizedMonthDay(birthDate, now.getFullYear());
  const today = now.toISOString().slice(0, 10);
  return thisYear >= today
    ? thisYear
    : normalizedMonthDay(birthDate, now.getFullYear() + 1);
}

function nextBirthdayAge(birthDate, from = new Date()) {
  const next = nextBirthdayDate(birthDate, from);
  return parseInt(next.slice(0, 4), 10) - parseInt(String(birthDate).slice(0, 4), 10);
}

function daysUntilBirthday(birthDate, from = new Date()) {
  const now = from instanceof Date ? from : new Date(from);
  const next = nextBirthdayDate(birthDate, now);
  const todayUtc = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());
  const nextUtc = Date.UTC(
    parseInt(next.slice(0, 4), 10),
    parseInt(next.slice(5, 7), 10) - 1,
    parseInt(next.slice(8, 10), 10),
  );
  return Math.round((nextUtc - todayUtc) / 86400000);
}

function birthdayReminderAt(birthDate, from = new Date()) {
  const next = nextBirthdayDate(birthDate, from);
  return `${next}T12:00:00Z`;
}

function eventTitle(name) {
  return `Birthday: ${name}`;
}

function eventDescription(name, birthDate) {
  return `Birthday reminder for ${name} (${birthDate}).`;
}

function syncBirthdayCalendarEvent(database, birthday) {
  const payload = {
    title: eventTitle(birthday.name),
    description: eventDescription(birthday.name, birthday.birth_date),
    start_datetime: birthday.birth_date,
    end_datetime: null,
    all_day: 1,
    location: null,
    color: BIRTHDAY_COLOR,
    icon: 'cake',
    assigned_to: null,
    recurrence_rule: BIRTHDAY_RRULE,
    created_by: birthday.created_by,
  };

  if (birthday.calendar_event_id) {
    const existing = database.prepare('SELECT id FROM calendar_events WHERE id = ?').get(birthday.calendar_event_id);
    if (existing) {
      database.prepare(`
        UPDATE calendar_events
        SET title = ?, description = ?, start_datetime = ?, end_datetime = ?, all_day = ?,
            location = ?, color = ?, icon = ?, assigned_to = ?, recurrence_rule = ?, created_by = ?,
            external_source = 'local'
        WHERE id = ?
      `).run(
        payload.title,
        payload.description,
        payload.start_datetime,
        payload.end_datetime,
        payload.all_day,
        payload.location,
        payload.color,
        payload.icon,
        payload.assigned_to,
        payload.recurrence_rule,
        payload.created_by,
        birthday.calendar_event_id,
      );
      return birthday.calendar_event_id;
    }
  }

  const result = database.prepare(`
    INSERT INTO calendar_events
      (title, description, start_datetime, end_datetime, all_day, location, color,
       icon, assigned_to, created_by, recurrence_rule, external_source)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'local')
  `).run(
    payload.title,
    payload.description,
    payload.start_datetime,
    payload.end_datetime,
    payload.all_day,
    payload.location,
    payload.color,
    payload.icon,
    payload.assigned_to,
    payload.created_by,
    payload.recurrence_rule,
  );

  database.prepare('UPDATE birthdays SET calendar_event_id = ? WHERE id = ?')
    .run(result.lastInsertRowid, birthday.id);
  return result.lastInsertRowid;
}

function syncBirthdayReminder(database, birthday, from = new Date()) {
  if (!birthday.calendar_event_id) return null;

  const desired = birthdayReminderAt(birthday.birth_date, from);
  const existing = database.prepare(`
    SELECT * FROM reminders
    WHERE entity_type = 'event' AND entity_id = ? AND created_by = ?
    ORDER BY created_at DESC
  `).all(birthday.calendar_event_id, birthday.created_by);

  const active = existing.find((row) => row.dismissed === 0);
  if (active && active.remind_at === desired) return active.id;

  database.prepare(`
    DELETE FROM reminders
    WHERE entity_type = 'event' AND entity_id = ? AND created_by = ?
  `).run(birthday.calendar_event_id, birthday.created_by);

  const result = database.prepare(`
    INSERT INTO reminders (entity_type, entity_id, remind_at, created_by)
    VALUES ('event', ?, ?, ?)
  `).run(birthday.calendar_event_id, desired, birthday.created_by);

  return result.lastInsertRowid;
}

function syncBirthdayArtifacts(database, birthday, from = new Date()) {
  const calendarEventId = syncBirthdayCalendarEvent(database, birthday);
  const refreshed = { ...birthday, calendar_event_id: calendarEventId };
  syncBirthdayReminder(database, refreshed, from);
  return refreshed;
}

function deleteBirthdayArtifacts(database, birthday) {
  if (birthday.calendar_event_id) {
    database.prepare(`
      DELETE FROM reminders
      WHERE entity_type = 'event' AND entity_id = ? AND created_by = ?
    `).run(birthday.calendar_event_id, birthday.created_by);
    database.prepare('DELETE FROM calendar_events WHERE id = ?').run(birthday.calendar_event_id);
  }
}

function hydrateBirthday(row, from = new Date()) {
  const next_birthday = nextBirthdayDate(row.birth_date, from);
  return {
    ...row,
    next_birthday,
    next_age: nextBirthdayAge(row.birth_date, from),
    days_until: daysUntilBirthday(row.birth_date, from),
  };
}

function syncAllBirthdayReminders(database, userId, from = new Date()) {
  const birthdays = database.prepare(`
    SELECT * FROM birthdays WHERE created_by = ? ORDER BY birth_date ASC
  `).all(userId);
  birthdays.forEach((birthday) => {
    const refreshed = birthday.calendar_event_id ? birthday : {
      ...birthday,
      calendar_event_id: syncBirthdayCalendarEvent(database, birthday),
    };
    syncBirthdayReminder(database, refreshed, from);
  });
}

export {
  BIRTHDAY_COLOR,
  BIRTHDAY_RRULE,
  birthdayReminderAt,
  daysUntilBirthday,
  deleteBirthdayArtifacts,
  eventDescription,
  eventTitle,
  hydrateBirthday,
  nextBirthdayAge,
  nextBirthdayDate,
  syncAllBirthdayReminders,
  syncBirthdayArtifacts,
};
