import { formatInTimeZone } from 'date-fns-tz';
import { Between } from 'typeorm';
import {
  AttendanceStatusEnum,
  AttendanceTypeEnum,
} from '../config/database/entities';
import type { DatabaseService } from '../config';
import { getUtcStartEndOfDate } from './helpers';

const workedStatuses = new Set<AttendanceStatusEnum>([
  AttendanceStatusEnum.present,
  AttendanceStatusEnum.late,
  AttendanceStatusEnum.half_day,
  AttendanceStatusEnum.check_in,
  AttendanceStatusEnum.on_break,
]);

export async function applyDayOffAttendance(
  db: DatabaseService,
  params: {
    member_id: string;
    owner_id: string;
    date: Date;
    reason: string;
    timeZone: string;
    notePrefix?: string;
  },
): Promise<string> {
  const notePrefix = params.notePrefix ?? 'Day off approved';
  const dateKey = formatInTimeZone(params.date, params.timeZone, 'yyyy-MM-dd');
  const { startUtc, endUtc } = getUtcStartEndOfDate(dateKey, params.timeZone);
  const note = `${notePrefix}: ${params.reason}`;

  const existing = await db.attendances.findFirst({
    where: {
      member_id: params.member_id,
      owner_id: params.owner_id,
      date: Between(startUtc, endUtc),
    },
  });

  if (existing) {
    const updateData: {
      note: string;
      status?: AttendanceStatusEnum;
    } = { note };

    if (!workedStatuses.has(existing.status)) {
      updateData.status = AttendanceStatusEnum.weekend;
    }

    const updated = await db.attendances.update({
      where: { id: existing.id },
      data: updateData,
    });
    return updated.id;
  }

  const created = await db.attendances.create({
    data: {
      member_id: params.member_id,
      owner_id: params.owner_id,
      date: startUtc,
      status: AttendanceStatusEnum.weekend,
      type: AttendanceTypeEnum.in_office,
      note,
    },
  });
  return created.id;
}

export async function revertDayOffAttendance(
  db: DatabaseService,
  params: {
    member_id: string;
    owner_id: string;
    date: Date;
    timeZone: string;
    notePrefix?: string;
  },
): Promise<void> {
  const notePrefix = params.notePrefix ?? 'Day off approved';
  const dateKey = formatInTimeZone(params.date, params.timeZone, 'yyyy-MM-dd');
  const { startUtc, endUtc } = getUtcStartEndOfDate(dateKey, params.timeZone);

  const existing = await db.attendances.findFirst({
    where: {
      member_id: params.member_id,
      owner_id: params.owner_id,
      date: Between(startUtc, endUtc),
    },
  });

  if (!existing) return;

  const noteMatches =
    existing.note?.startsWith(`${notePrefix}:`) ||
    existing.note?.startsWith('Off-day work request approved:');

  if (!noteMatches) return;

  if (workedStatuses.has(existing.status)) {
    await db.attendances.update({
      where: { id: existing.id },
      data: { note: '' },
    });
    return;
  }

  await db.attendances.update({
    where: { id: existing.id },
    data: {
      status: AttendanceStatusEnum.absent,
      note: '',
    },
  });
}
