import { eq } from 'drizzle-orm';
import { NextRequest, NextResponse } from 'next/server';
import { onlineLessons } from '@/db/schema';
import {
  canCreateContent,
  canTransitionContent,
  getNextContentStatus
} from '@/features/content-approval/lib/workflow';
import {
  AUDIT_ACTION,
  AUDIT_MODULE,
  getRequestMetadata,
  logAuditEvent,
  toAuditValue
} from '@/features/audit-logs/server/audit-service';
import {
  onlineLessonDraftActionSchema,
  onlineLessonDraftSchema,
  validateOnlineLessonReadyForReview
} from '@/features/online-lessons/schemas/online-lesson';
import {
  getOnlineLessonReviewRecipientIds,
  listOnlineLessonsForAccess,
  serializeOnlineLesson
} from '@/features/online-lessons/server/online-lesson-data';
import { normalizeOnlineLessonCategory } from '@/features/online-lessons/constants/categories';
import { createContentWorkflowNotification } from '@/features/notifications/server/notification-service';
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
import { getDatabaseErrorMessage } from '@/lib/db-errors';
import { db } from '@/lib/db';
import {
  ONLINE_LESSON_ACCEPTED_ATTACHMENT_TYPES,
  ONLINE_LESSON_ACCEPTED_THUMBNAIL_TYPES,
  ONLINE_LESSON_ACCEPTED_VIDEO_TYPES,
  ONLINE_LESSON_MAX_ATTACHMENT_SIZE,
  ONLINE_LESSON_MAX_THUMBNAIL_SIZE,
  ONLINE_LESSON_MAX_VIDEO_SIZE,
  saveOnlineLessonAttachment,
  saveOnlineLessonThumbnail,
  saveOnlineLessonVideo
} from '@/lib/online-lesson-storage';

function parseBooleanValue(value: FormDataEntryValue | null) {
  return value === 'true';
}

function normalizeTextValue(value: FormDataEntryValue | null) {
  if (typeof value !== 'string') return '';
  return value.trim();
}

function validateOptionalFile({
  file,
  acceptedTypes,
  maxSize,
  errorMessage,
  sizeErrorMessage
}: {
  file: File | null;
  acceptedTypes: readonly string[];
  maxSize: number;
  errorMessage: string;
  sizeErrorMessage: string;
}) {
  if (!file || file.size === 0) return null;

  if (!acceptedTypes.includes(file.type)) {
    throw new Error(errorMessage);
  }

  if (file.size > maxSize) {
    throw new Error(sizeErrorMessage);
  }

  return file;
}

async function parseOnlineLessonFormData(request: NextRequest) {
  const formData = await request.formData();
  const rawValues = {
    title: String(formData.get('title') ?? ''),
    description: String(formData.get('description') ?? ''),
    category: normalizeOnlineLessonCategory(String(formData.get('category') ?? '')),
    videoUrl: normalizeTextValue(formData.get('videoUrl')) || undefined
  };

  const parsedValues = onlineLessonDraftSchema.safeParse(rawValues);
  if (!parsedValues.success) {
    throw new Error(parsedValues.error.issues[0]?.message ?? 'ข้อมูลบทเรียนออนไลน์ไม่ถูกต้อง');
  }

  const parsedAction = onlineLessonDraftActionSchema.safeParse(
    String(formData.get('action') ?? 'draft')
  );
  if (!parsedAction.success) {
    throw new Error('คำสั่งการบันทึกบทเรียนไม่ถูกต้อง');
  }

  return {
    action: parsedAction.data,
    values: parsedValues.data,
    removeVideoFile: parseBooleanValue(formData.get('removeVideoFile')),
    removeAttachment: parseBooleanValue(formData.get('removeAttachment')),
    removeThumbnail: parseBooleanValue(formData.get('removeThumbnail')),
    videoFile: validateOptionalFile({
      file: formData.get('videoFile') as File | null,
      acceptedTypes: ONLINE_LESSON_ACCEPTED_VIDEO_TYPES,
      maxSize: ONLINE_LESSON_MAX_VIDEO_SIZE,
      errorMessage: 'รองรับไฟล์วิดีโอ MP4, WEBM และ MOV เท่านั้น',
      sizeErrorMessage: 'ไฟล์วิดีโอต้องมีขนาดไม่เกิน 200MB'
    }),
    attachmentFile: validateOptionalFile({
      file: formData.get('attachmentFile') as File | null,
      acceptedTypes: ONLINE_LESSON_ACCEPTED_ATTACHMENT_TYPES,
      maxSize: ONLINE_LESSON_MAX_ATTACHMENT_SIZE,
      errorMessage: 'ไฟล์แนบไม่อยู่ในรูปแบบที่รองรับ',
      sizeErrorMessage: 'ไฟล์แนบต้องมีขนาดไม่เกิน 20MB'
    }),
    thumbnailFile: validateOptionalFile({
      file: formData.get('thumbnailFile') as File | null,
      acceptedTypes: ONLINE_LESSON_ACCEPTED_THUMBNAIL_TYPES,
      maxSize: ONLINE_LESSON_MAX_THUMBNAIL_SIZE,
      errorMessage: 'รูปปกต้องเป็น JPG, PNG หรือ WEBP เท่านั้น',
      sizeErrorMessage: 'รูปปกต้องมีขนาดไม่เกิน 5MB'
    })
  };
}

export async function GET(request: NextRequest) {
  try {
    const { organization, session } = await requireOrganizationAccess();
    const { searchParams } = request.nextUrl;

    const result = await listOnlineLessonsForAccess({
      organizationId: organization.id,
      permissions: session.user.effectivePermissions,
      filters: {
        page: Number(searchParams.get('page') ?? 1),
        limit: Number(searchParams.get('limit') ?? 12),
        search: searchParams.get('search') ?? undefined,
        status: (searchParams.get('status') as
          | 'draft'
          | 'pending_review'
          | 'approved'
          | 'published'
          | 'returned'
          | 'rejected'
          | 'archived'
          | null) ?? undefined,
        category: normalizeOnlineLessonCategory(searchParams.get('category')) ?? undefined
      }
    });

    return NextResponse.json({
      success: true,
      time: new Date().toISOString(),
      message: 'โหลดบทเรียนออนไลน์เรียบร้อยแล้ว',
      total_online_lessons: result.total,
      offset: result.offset,
      limit: result.limit,
      categories: result.categories,
      online_lessons: result.onlineLessons
    });
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    return NextResponse.json({ message: 'ไม่สามารถโหลดบทเรียนออนไลน์ได้' }, { status: 500 });
  }
}

export async function POST(request: NextRequest) {
  try {
    const { organization, session } = await requireOrganizationAccess();
    const requestMetadata = getRequestMetadata(request);
    const { action, values, videoFile, attachmentFile, thumbnailFile } =
      await parseOnlineLessonFormData(request);
    const permissions = session.user.effectivePermissions;

    if (!canCreateContent('online_lesson', permissions)) {
      return NextResponse.json({ message: 'Forbidden' }, { status: 403 });
    }

    const wantsSubmit = action === 'submit';
    if (
      wantsSubmit &&
      !canTransitionContent({
        module: 'online_lesson',
        action: 'submit',
        currentStatus: 'draft',
        permissions,
        isOwner: true
      })
    ) {
      return NextResponse.json({ message: 'ไม่มีสิทธิ์ส่งบทเรียนเพื่อตรวจสอบ' }, { status: 403 });
    }

    if (wantsSubmit) {
      validateOnlineLessonReadyForReview({
        values,
        hasThumbnailSource: Boolean(thumbnailFile)
      });
    }

    const initialStatus = wantsSubmit ? getNextContentStatus('submit') : 'draft';

    const [created] = await db
      .insert(onlineLessons)
      .values({
        organizationId: organization.id,
        title: values.title.trim(),
        description: values.description?.trim() || null,
        category: values.category?.trim() || null,
        videoUrl: values.videoUrl?.trim() || null,
        status: initialStatus,
        submittedAt: wantsSubmit ? new Date() : null,
        submittedBy: wantsSubmit ? session.user.id : null,
        isPublished: false,
        publishedAt: null,
        createdBy: session.user.id,
        updatedBy: session.user.id
      })
      .returning();

    let record = created;

    if (videoFile) {
      const storedVideo = await saveOnlineLessonVideo({
        file: videoFile,
        organizationId: organization.id,
        lessonId: created.id
      });

      [record] = await db
        .update(onlineLessons)
        .set({
          videoFileName: storedVideo.fileName,
          videoFileType: storedVideo.fileType,
          videoFileSize: storedVideo.fileSize,
          videoStorageKey: storedVideo.storageKey,
          videoFileUrl: storedVideo.fileUrl,
          updatedAt: new Date(),
          updatedBy: session.user.id
        })
        .where(eq(onlineLessons.id, created.id))
        .returning();
    }

    if (attachmentFile) {
      const storedAttachment = await saveOnlineLessonAttachment({
        file: attachmentFile,
        organizationId: organization.id,
        lessonId: created.id
      });

      [record] = await db
        .update(onlineLessons)
        .set({
          attachmentFileName: storedAttachment.fileName,
          attachmentFileType: storedAttachment.fileType,
          attachmentFileSize: storedAttachment.fileSize,
          attachmentStorageKey: storedAttachment.storageKey,
          attachmentFileUrl: storedAttachment.fileUrl,
          updatedAt: new Date(),
          updatedBy: session.user.id
        })
        .where(eq(onlineLessons.id, created.id))
        .returning();
    }

    if (thumbnailFile) {
      const storedThumbnail = await saveOnlineLessonThumbnail({
        file: thumbnailFile,
        organizationId: organization.id,
        lessonId: created.id
      });

      [record] = await db
        .update(onlineLessons)
        .set({
          thumbnailFileName: storedThumbnail.fileName,
          thumbnailFileType: storedThumbnail.fileType,
          thumbnailFileSize: storedThumbnail.fileSize,
          thumbnailStorageKey: storedThumbnail.storageKey,
          thumbnailUrl: storedThumbnail.fileUrl,
          updatedAt: new Date(),
          updatedBy: session.user.id
        })
        .where(eq(onlineLessons.id, created.id))
        .returning();
    }

    const serializedLesson = serializeOnlineLesson({
      ...record,
      createdByName: session.user.name ?? session.user.email ?? null,
      updatedByName: session.user.name ?? session.user.email ?? null
    });

    await logAuditEvent({
      organizationId: organization.id,
      userId: session.user.id,
      module: AUDIT_MODULE.ONLINE_LESSONS,
      action: AUDIT_ACTION.ONLINE_LESSON_CREATE,
      entityName: record.title,
      entityId: record.id,
      newValue: toAuditValue(serializedLesson),
      ...requestMetadata
    });

    if (wantsSubmit) {
      await logAuditEvent({
        organizationId: organization.id,
        userId: session.user.id,
        module: AUDIT_MODULE.ONLINE_LESSONS,
        action: AUDIT_ACTION.ONLINE_LESSON_SUBMIT,
        entityName: record.title,
        entityId: record.id,
        newValue: toAuditValue(serializedLesson),
        ...requestMetadata
      });

      const reviewerIds = await getOnlineLessonReviewRecipientIds({
        organizationId: organization.id,
        excludeUserIds: [session.user.id]
      });

      await Promise.all(
        reviewerIds.map((userId) =>
          createContentWorkflowNotification({
            organizationId: organization.id,
            userId,
            title: `มีบทเรียนใหม่รอตรวจสอบ: ${record.title}`,
            message: 'มีการส่งบทเรียนออนไลน์เข้าสู่คิวตรวจสอบ กรุณาเปิดเพื่อตรวจสอบและอนุมัติ',
            type: 'CONTENT_SUBMITTED',
            referenceId: record.id,
            referenceType: 'content_submission'
          })
        )
      );
    } else {
      await logAuditEvent({
        organizationId: organization.id,
        userId: session.user.id,
        module: AUDIT_MODULE.ONLINE_LESSONS,
        action: AUDIT_ACTION.ONLINE_LESSON_DRAFT_SAVED,
        entityName: record.title,
        entityId: record.id,
        newValue: toAuditValue(serializedLesson),
        ...requestMetadata
      });
    }

    return NextResponse.json(
      {
        success: true,
        time: new Date().toISOString(),
        message: wantsSubmit
          ? 'ส่งบทเรียนเพื่อตรวจสอบเรียบร้อยแล้ว'
          : 'บันทึกบทเรียนฉบับร่างเรียบร้อยแล้ว',
        online_lesson: serializedLesson
      },
      { status: 201 }
    );
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    if (error instanceof Error && !error.message.includes('Database')) {
      return NextResponse.json({ message: error.message }, { status: 400 });
    }

    console.error('Failed to create online lesson', error);
    return NextResponse.json({ message: getDatabaseErrorMessage(error) }, { status: 500 });
  }
}
