import { and, asc, count, desc, eq, gte, ilike, lt, or } from 'drizzle-orm';
import { auditLogs, users } from '@/db/schema';
import { db } from '@/lib/db';
import type { AuditLogFilters } from '../api/types';

type AuditLogRow = {
  id: number;
  organizationId: string | null;
  userId: string | null;
  userName: string | null;
  userEmail: string | null;
  moduleName: string;
  action: string;
  entityName: string | null;
  entityId: string | null;
  oldValue: Record<string, unknown> | null;
  newValue: Record<string, unknown> | null;
  ipAddress: string | null;
  userAgent: string | null;
  createdAt: Date;
};

const sortMap = {
  created_at: auditLogs.createdAt,
  user_name: users.name,
  module_name: auditLogs.moduleName,
  action: auditLogs.action
} as const;

function normalizeText(value?: string | null) {
  const normalized = value?.trim();
  return normalized ? normalized : null;
}

function toDate(value: string, endOfDay: boolean) {
  return new Date(`${value}T${endOfDay ? '23:59:59.999' : '00:00:00.000'}Z`);
}

function readText(value: Record<string, unknown> | null, key: string) {
  const raw = value?.[key];
  return typeof raw === 'string' && raw.trim() ? raw.trim() : null;
}

function readNumber(value: Record<string, unknown> | null, key: string) {
  const raw = value?.[key];
  return typeof raw === 'number' ? raw : null;
}

function formatMasterReviewTarget(entityName: string | null, value: Record<string, unknown> | null) {
  const targetType = readText(value, 'entityType');
  const label =
    targetType === 'company'
      ? 'บริษัท'
      : targetType === 'department'
        ? 'แผนก'
        : targetType === 'position'
          ? 'ตำแหน่ง'
          : 'ข้อมูลหลัก';

  return `${label}${entityName ? ` ${entityName}` : ''}`;
}

export function formatAuditDetails(log: AuditLogRow) {
  switch (log.moduleName) {
    case 'AUTHENTICATION': {
      const email = readText(log.newValue, 'email') ?? log.userEmail ?? log.userName ?? 'ไม่ทราบผู้ใช้';
      const reason = readText(log.newValue, 'reason');

      if (log.action === 'LOGIN_SUCCESS') {
        return `เข้าสู่ระบบด้วย ${email}`;
      }

      return reason
        ? `พยายามเข้าสู่ระบบด้วย ${email} ไม่สำเร็จ: ${reason}`
        : `พยายามเข้าสู่ระบบด้วย ${email} ไม่สำเร็จ`;
    }

    case 'TRAINING_RECORDS': {
      const courseName =
        readText(log.newValue, 'course_name') ??
        readText(log.oldValue, 'course_name') ??
        log.entityName ??
        'ไม่ระบุหลักสูตร';

      return log.action === 'DELETE'
        ? `ลบรายการอบรม ${courseName}`
        : log.action === 'UPDATE'
          ? `แก้ไขรายการอบรม ${courseName}`
          : `สร้างรายการอบรม ${courseName}`;
    }

    case 'HRD_REVIEW': {
      const courseName =
        readText(log.newValue, 'course_name') ??
        readText(log.oldValue, 'course_name') ??
        log.entityName ??
        'ไม่ระบุหลักสูตร';

      if (log.action === 'APPROVE') {
        const approvedHours = readNumber(log.newValue, 'approved_hours');
        return approvedHours === null
          ? `อนุมัติรายการอบรม ${courseName}`
          : `อนุมัติรายการอบรม ${courseName} ${approvedHours} ชั่วโมง`;
      }

      const rejectReason = readText(log.newValue, 'reject_reason');
      return rejectReason
        ? `ไม่อนุมัติรายการอบรม ${courseName}: ${rejectReason}`
        : `ไม่อนุมัติรายการอบรม ${courseName}`;
    }

    case 'COURSE_MASTER': {
      const courseName =
        readText(log.newValue, 'name') ?? readText(log.oldValue, 'name') ?? log.entityName ?? 'ไม่ระบุหลักสูตร';
      return log.action === 'CREATE'
        ? `สร้างหลักสูตร ${courseName}`
        : `แก้ไขหลักสูตร ${courseName}`;
    }

    case 'TRAINING_POLICY': {
      const year = log.newValue?.year ?? log.oldValue?.year ?? log.entityId;
      if (log.action === 'CREATE') {
        return `สร้างนโยบายอบรมปี ${year ?? '-'}`;
      }

      if (log.action === 'CLONE') {
        const sourceYear = log.oldValue?.year ?? '-';
        return `โคลนนโยบายอบรมจากปี ${sourceYear} เป็นปี ${year ?? '-'}`;
      }

      if (log.action === 'ACTIVATE') {
        return `เปิดใช้งานนโยบายอบรมปี ${year ?? '-'}`;
      }

      if (log.action === 'DEACTIVATE') {
        return `ปิดใช้งานนโยบายอบรมปี ${year ?? '-'}`;
      }

      return `แก้ไขนโยบายอบรมปี ${year ?? '-'}`;
    }

    case 'EMPLOYEE_IMPORT': {
      const employeeCode =
        readText(log.newValue, 'employeeCode') ?? readText(log.oldValue, 'employeeCode');
      const targetYear = log.newValue?.year ?? log.oldValue?.year;

      if (log.action === 'EMPLOYEE_TARGET_CREATE') {
        return `สร้างเป้าหมายอบรมรายบุคคล ${employeeCode ?? log.entityName ?? '-'} ปี ${targetYear ?? '-'}`;
      }

      if (log.action === 'EMPLOYEE_TARGET_UPDATE') {
        return `อัปเดตเป้าหมายอบรมรายบุคคล ${employeeCode ?? log.entityName ?? '-'} ปี ${targetYear ?? '-'}`;
      }

      const fileName = readText(log.newValue, 'file_name') ?? log.entityName ?? 'ไม่ระบุไฟล์';
      const summary = log.newValue?.summary;

      if (summary && typeof summary === 'object') {
        const createdUsers = (summary as Record<string, unknown>).created_users;
        const updatedUsers = (summary as Record<string, unknown>).updated_users;
        const importedTargets = (summary as Record<string, unknown>).imported_targets;
        const successRows =
          typeof createdUsers === 'number' && typeof updatedUsers === 'number'
            ? createdUsers + updatedUsers
            : null;

        if (successRows !== null) {
          return `นำเข้าพนักงานจาก ${fileName} สำเร็จ ${successRows} รายการ และนำเข้าเป้าหมาย ${typeof importedTargets === 'number' ? importedTargets : 0} รายการ`;
        }
      }

      return `นำเข้าพนักงานจาก ${fileName}`;
    }

    case 'MASTER_REVIEW': {
      const target = formatMasterReviewTarget(
        log.entityName,
        (log.newValue ?? log.oldValue) as Record<string, unknown> | null
      );
      return log.action === 'APPROVE' ? `อนุมัติ${target}` : `ไม่อนุมัติ${target}`;
    }

    case 'ANNOUNCEMENTS': {
      const title = readText(log.newValue, 'title') ?? readText(log.oldValue, 'title') ?? log.entityName ?? 'ประกาศ';

      if (log.action === 'ANNOUNCEMENT_PINNED') {
        return `ปักหมุดประกาศ ${title}`;
      }

      if (log.action === 'ANNOUNCEMENT_UNPINNED') {
        return `ยกเลิกปักหมุดประกาศ ${title}`;
      }

      return log.entityName ?? log.moduleName;
    }

    default:
      return log.entityName ?? log.moduleName;
  }
}

export function serializeAuditLog(log: AuditLogRow) {
  return {
    id: log.id,
    organization_id: log.organizationId,
    user_id: log.userId,
    user_name: log.userName,
    user_email: log.userEmail,
    module_name: log.moduleName,
    action: log.action,
    entity_name: log.entityName,
    entity_id: log.entityId,
    old_value: log.oldValue,
    new_value: log.newValue,
    ip_address: log.ipAddress,
    user_agent: log.userAgent,
    details: formatAuditDetails(log),
    created_at: log.createdAt.toISOString()
  };
}

export async function listAuditLogsForOrganization({
  organizationId,
  filters
}: {
  organizationId: string;
  filters: AuditLogFilters;
}) {
  const page = Number(filters.page ?? 1);
  const limit = Number(filters.limit ?? 10);
  const search = normalizeText(filters.search);
  const userSearch = normalizeText(filters.user);
  const moduleName = normalizeText(filters.module);
  const action = normalizeText(filters.action);
  const dateFrom = normalizeText(filters.dateFrom);
  const dateTo = normalizeText(filters.dateTo);

  const clauses = [
    eq(auditLogs.organizationId, organizationId),
    ...(moduleName ? [eq(auditLogs.moduleName, moduleName)] : []),
    ...(action ? [eq(auditLogs.action, action)] : []),
    ...(userSearch
      ? [or(ilike(users.name, `%${userSearch}%`), ilike(users.email, `%${userSearch}%`))!]
      : []),
    ...(dateFrom ? [gte(auditLogs.createdAt, toDate(dateFrom, false))] : []),
    ...(dateTo ? [lt(auditLogs.createdAt, new Date(toDate(dateTo, true).getTime() + 1))] : []),
    ...(search
      ? [
          or(
            ilike(users.name, `%${search}%`),
            ilike(users.email, `%${search}%`),
            ilike(auditLogs.moduleName, `%${search}%`),
            ilike(auditLogs.action, `%${search}%`),
            ilike(auditLogs.entityName, `%${search}%`),
            ilike(auditLogs.entityId, `%${search}%`)
          )!
        ]
      : [])
  ];

  const where = clauses.length === 1 ? clauses[0] : and(...clauses);
  let orderByClause = desc(auditLogs.createdAt);

  if (filters.sort) {
    try {
      const sortItems = JSON.parse(filters.sort) as Array<{ id: keyof typeof sortMap; desc: boolean }>;
      const primarySort = sortItems[0];

      if (primarySort?.id && sortMap[primarySort.id]) {
        orderByClause = primarySort.desc ? desc(sortMap[primarySort.id]) : asc(sortMap[primarySort.id]);
      }
    } catch {
      orderByClause = desc(auditLogs.createdAt);
    }
  }

  const baseQuery = db
    .select({
      id: auditLogs.id,
      organizationId: auditLogs.organizationId,
      userId: auditLogs.userId,
      userName: users.name,
      userEmail: users.email,
      moduleName: auditLogs.moduleName,
      action: auditLogs.action,
      entityName: auditLogs.entityName,
      entityId: auditLogs.entityId,
      oldValue: auditLogs.oldValue,
      newValue: auditLogs.newValue,
      ipAddress: auditLogs.ipAddress,
      userAgent: auditLogs.userAgent,
      createdAt: auditLogs.createdAt
    })
    .from(auditLogs)
    .leftJoin(users, eq(auditLogs.userId, users.id));

  const countSubquery = baseQuery.where(where).as('scoped_audit_logs');
  const [totalResult] = await db.select({ value: count() }).from(countSubquery);

  const offset = (page - 1) * limit;
  const rows = await baseQuery.where(where).orderBy(orderByClause).limit(limit).offset(offset);

  return {
    offset,
    limit,
    total: totalResult?.value ?? 0,
    auditLogs: rows.map((row) => serializeAuditLog(row as AuditLogRow))
  };
}
