import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
import path from 'node:path';

export const ONLINE_LESSON_MAX_VIDEO_SIZE = 200 * 1024 * 1024;
export const ONLINE_LESSON_MAX_ATTACHMENT_SIZE = 20 * 1024 * 1024;
export const ONLINE_LESSON_MAX_THUMBNAIL_SIZE = 5 * 1024 * 1024;

export const ONLINE_LESSON_ACCEPTED_VIDEO_TYPES = [
  'video/mp4',
  'video/webm',
  'video/quicktime'
] as const;

export const ONLINE_LESSON_ACCEPTED_ATTACHMENT_TYPES = [
  'application/pdf',
  'application/msword',
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  'application/vnd.ms-excel',
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  'application/vnd.ms-powerpoint',
  'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  'image/jpeg',
  'image/jpg',
  'image/png',
  'application/zip',
  'application/x-zip-compressed'
] as const;

export const ONLINE_LESSON_ACCEPTED_THUMBNAIL_TYPES = [
  'image/jpeg',
  'image/jpg',
  'image/png',
  'image/webp'
] as const;

const PUBLIC_UPLOAD_ROOT = path.join(process.cwd(), 'public', 'uploads', 'online-lessons');

function sanitizeSegment(value: string) {
  return value.replace(/[^a-zA-Z0-9._-]/g, '-');
}

function ensureWithinUploadRoot(targetPath: string) {
  const normalizedRoot = path.resolve(PUBLIC_UPLOAD_ROOT);
  const normalizedTarget = path.resolve(targetPath);

  if (!normalizedTarget.startsWith(normalizedRoot)) {
    throw new Error('Invalid online lesson storage path');
  }
}

async function saveOnlineLessonAsset({
  file,
  organizationId,
  lessonId,
  assetType
}: {
  file: File;
  organizationId: string;
  lessonId: number | string;
  assetType: 'video' | 'attachment' | 'thumbnail';
}) {
  const extension = path.extname(file.name) || '.bin';
  const baseName = sanitizeSegment(path.basename(file.name, extension)) || assetType;
  const uniqueName = `${Date.now()}-${crypto.randomUUID()}-${baseName}${extension}`;
  const storageKey = path.join(
    sanitizeSegment(organizationId),
    String(lessonId),
    assetType,
    uniqueName
  );
  const absoluteDirectory = path.join(
    PUBLIC_UPLOAD_ROOT,
    sanitizeSegment(organizationId),
    String(lessonId),
    assetType
  );
  const absolutePath = path.join(absoluteDirectory, uniqueName);

  ensureWithinUploadRoot(absolutePath);
  await mkdir(absoluteDirectory, { recursive: true });
  const bytes = Buffer.from(await file.arrayBuffer());
  await writeFile(absolutePath, bytes);

  return {
    storageKey: storageKey.replaceAll('\\', '/'),
    fileUrl: `/uploads/online-lessons/${storageKey.replaceAll('\\', '/')}`,
    fileName: file.name,
    fileType: file.type,
    fileSize: file.size
  };
}

export async function saveOnlineLessonVideo(args: {
  file: File;
  organizationId: string;
  lessonId: number | string;
}) {
  return saveOnlineLessonAsset({ ...args, assetType: 'video' });
}

export async function saveOnlineLessonAttachment(args: {
  file: File;
  organizationId: string;
  lessonId: number | string;
}) {
  return saveOnlineLessonAsset({ ...args, assetType: 'attachment' });
}

export async function saveOnlineLessonThumbnail(args: {
  file: File;
  organizationId: string;
  lessonId: number | string;
}) {
  return saveOnlineLessonAsset({ ...args, assetType: 'thumbnail' });
}

export async function deleteStoredOnlineLessonAsset(storageKey: string) {
  const absolutePath = path.join(PUBLIC_UPLOAD_ROOT, storageKey);
  ensureWithinUploadRoot(absolutePath);

  try {
    await unlink(absolutePath);
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
      throw error;
    }
  }
}

export async function readStoredOnlineLessonAsset(storageKey: string) {
  const absolutePath = path.join(PUBLIC_UPLOAD_ROOT, storageKey);
  ensureWithinUploadRoot(absolutePath);

  return readFile(absolutePath);
}
