import { and, eq } from 'drizzle-orm';
import { NextRequest, NextResponse } from 'next/server';
import { onlineLessons } from '@/db/schema';
import {
  canDeleteContent,
  canEditContent,
  canReadAllContent,
  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 { normalizeOnlineLessonCategory } from '@/features/online-lessons/constants/categories';
import {
  getOnlineLessonByIdForAccess,
  getOnlineLessonReviewRecipientIds,
  serializeOnlineLesson
} from '@/features/online-lessons/server/online-lesson-data';
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 {
  deleteStoredOnlineLessonAsset,
  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 parseId(value: string) {
  const id = Number(value);
  if (Number.isNaN(id)) {
    throw new Error('รหัสบทเรียนออนไลน์ไม่ถูกต้อง');
  }
  return id;
}

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

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

function buildWorkflowMessage(comment: string | null, fallback: string) {
  return comment ? `${fallback} หมายเหตุ: ${comment}` : fallback;
}

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,
  context: { params: Promise<{ id: string }> }
) {
  try {
    const { organization, session } = await requireOrganizationAccess();
    const { id: rawId } = await context.params;
    const id = parseId(rawId);

    const row = await getOnlineLessonByIdForAccess({
      id,
      organizationId: organization.id,
      permissions: session.user.effectivePermissions
    });

    if (!row) {
      return NextResponse.json({ message: 'ไม่พบบทเรียนออนไลน์' }, { status: 404 });
    }

    return NextResponse.json({
      success: true,
      time: new Date().toISOString(),
      message: 'โหลดรายละเอียดบทเรียนออนไลน์เรียบร้อยแล้ว',
      online_lesson: serializeOnlineLesson(row, {
        includeInternalReviewData: canReadAllContent(
          'online_lesson',
          session.user.effectivePermissions
        )
      })
    });
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    if (error instanceof Error) {
      return NextResponse.json({ message: error.message }, { status: 400 });
    }

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

export async function PATCH(
  request: NextRequest,
  context: { params: Promise<{ id: string }> }
) {
  try {
    const { organization, session } = await requireOrganizationAccess();
    const requestMetadata = getRequestMetadata(request);
    const { id: rawId } = await context.params;
    const id = parseId(rawId);

    const [existing] = await db
      .select()
      .from(onlineLessons)
      .where(and(eq(onlineLessons.id, id), eq(onlineLessons.organizationId, organization.id)))
      .limit(1);

    if (!existing) {
      return NextResponse.json({ message: 'ไม่พบบทเรียนออนไลน์' }, { status: 404 });
    }

    const permissions = session.user.effectivePermissions;
    const isOwner = existing.createdBy === session.user.id;
    const previousSerialized = serializeOnlineLesson({
      ...existing,
      createdByName: null,
      updatedByName: null
    });

    const contentType = request.headers.get('content-type') ?? '';
    let nextStatus = existing.status;
    let reviewComment = existing.reviewComment;
    let multipartAction: 'draft' | 'submit' | null = null;
    let successMessage = 'อัปเดตบทเรียนออนไลน์เรียบร้อยแล้ว';

    if (contentType.includes('multipart/form-data')) {
      if (
        !canEditContent({
          module: 'online_lesson',
          permissions,
          status: existing.status,
          isOwner
        })
      ) {
        return NextResponse.json({ message: 'ไม่มีสิทธิ์แก้ไขบทเรียนในสถานะปัจจุบัน' }, { status: 403 });
      }

      const {
        action,
        values,
        removeVideoFile,
        removeAttachment,
        removeThumbnail,
        videoFile,
        attachmentFile,
        thumbnailFile
      } = await parseOnlineLessonFormData(request);

      multipartAction = action;

      const hasExistingThumbnail = Boolean(existing.thumbnailUrl && !removeThumbnail);
      const canSubmitAgain = canTransitionContent({
        module: 'online_lesson',
        action: 'submit',
        currentStatus: existing.status,
        permissions,
        isOwner
      });

      if (action === 'submit') {
        if (!canSubmitAgain) {
          return NextResponse.json({ message: 'ไม่มีสิทธิ์ส่งบทเรียนเพื่อตรวจสอบ' }, { status: 403 });
        }

        validateOnlineLessonReadyForReview({
          values,
          hasThumbnailSource: Boolean(thumbnailFile || hasExistingThumbnail)
        });

        nextStatus = getNextContentStatus('submit');
        successMessage = 'ส่งบทเรียนเพื่อตรวจสอบเรียบร้อยแล้ว';
      } else {
        nextStatus = existing.status;
        successMessage = canSubmitAgain
          ? 'บันทึกบทเรียนฉบับร่างเรียบร้อยแล้ว'
          : 'บันทึกการแก้ไขบทเรียนเรียบร้อยแล้ว';
      }

      await db
        .update(onlineLessons)
        .set({
          title: values.title.trim(),
          description: values.description?.trim() || null,
          category: values.category?.trim() || null,
          videoUrl: values.videoUrl?.trim() || null,
          status: nextStatus,
          submittedAt: action === 'submit' ? new Date() : existing.submittedAt,
          submittedBy: action === 'submit' ? session.user.id : existing.submittedBy,
          updatedBy: session.user.id,
          updatedAt: new Date(),
          ...(removeVideoFile && !videoFile
            ? {
                videoFileName: null,
                videoFileType: null,
                videoFileSize: null,
                videoStorageKey: null,
                videoFileUrl: null
              }
            : {}),
          ...(removeAttachment && !attachmentFile
            ? {
                attachmentFileName: null,
                attachmentFileType: null,
                attachmentFileSize: null,
                attachmentStorageKey: null,
                attachmentFileUrl: null
              }
            : {}),
          ...(removeThumbnail && !thumbnailFile
            ? {
                thumbnailFileName: null,
                thumbnailFileType: null,
                thumbnailFileSize: null,
                thumbnailStorageKey: null,
                thumbnailUrl: null
              }
            : {})
        })
        .where(and(eq(onlineLessons.id, id), eq(onlineLessons.organizationId, organization.id)));

      if (removeVideoFile && !videoFile && existing.videoStorageKey) {
        await deleteStoredOnlineLessonAsset(existing.videoStorageKey);
      }
      if (removeAttachment && !attachmentFile && existing.attachmentStorageKey) {
        await deleteStoredOnlineLessonAsset(existing.attachmentStorageKey);
      }
      if (removeThumbnail && !thumbnailFile && existing.thumbnailStorageKey) {
        await deleteStoredOnlineLessonAsset(existing.thumbnailStorageKey);
      }

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

        await db
          .update(onlineLessons)
          .set({
            videoFileName: storedVideo.fileName,
            videoFileType: storedVideo.fileType,
            videoFileSize: storedVideo.fileSize,
            videoStorageKey: storedVideo.storageKey,
            videoFileUrl: storedVideo.fileUrl,
            updatedBy: session.user.id,
            updatedAt: new Date()
          })
          .where(and(eq(onlineLessons.id, id), eq(onlineLessons.organizationId, organization.id)));

        if (existing.videoStorageKey) {
          await deleteStoredOnlineLessonAsset(existing.videoStorageKey);
        }
      }

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

        await db
          .update(onlineLessons)
          .set({
            attachmentFileName: storedAttachment.fileName,
            attachmentFileType: storedAttachment.fileType,
            attachmentFileSize: storedAttachment.fileSize,
            attachmentStorageKey: storedAttachment.storageKey,
            attachmentFileUrl: storedAttachment.fileUrl,
            updatedBy: session.user.id,
            updatedAt: new Date()
          })
          .where(and(eq(onlineLessons.id, id), eq(onlineLessons.organizationId, organization.id)));

        if (existing.attachmentStorageKey) {
          await deleteStoredOnlineLessonAsset(existing.attachmentStorageKey);
        }
      }

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

        await db
          .update(onlineLessons)
          .set({
            thumbnailFileName: storedThumbnail.fileName,
            thumbnailFileType: storedThumbnail.fileType,
            thumbnailFileSize: storedThumbnail.fileSize,
            thumbnailStorageKey: storedThumbnail.storageKey,
            thumbnailUrl: storedThumbnail.fileUrl,
            updatedBy: session.user.id,
            updatedAt: new Date()
          })
          .where(and(eq(onlineLessons.id, id), eq(onlineLessons.organizationId, organization.id)));

        if (existing.thumbnailStorageKey) {
          await deleteStoredOnlineLessonAsset(existing.thumbnailStorageKey);
        }
      }
    } else {
      const body = (await request.json()) as {
        action?: 'submit' | 'approve' | 'return' | 'reject' | 'publish' | 'archive';
        status?:
          | 'draft'
          | 'pending_review'
          | 'approved'
          | 'published'
          | 'returned'
          | 'rejected'
          | 'archived';
        comment?: string;
      };

      const normalizedAction =
        body.action ??
        (body.status === 'pending_review'
          ? 'submit'
          : body.status === 'published'
            ? 'publish'
            : body.status === 'archived'
              ? 'archive'
              : undefined);

      if (!normalizedAction) {
        return NextResponse.json({ message: 'ไม่มีข้อมูลสำหรับอัปเดต' }, { status: 400 });
      }

      if (
        !canTransitionContent({
          module: 'online_lesson',
          action: normalizedAction,
          currentStatus: existing.status,
          permissions,
          isOwner
        })
      ) {
        return NextResponse.json({ message: 'ไม่สามารถเปลี่ยนสถานะบทเรียนได้' }, { status: 403 });
      }

      nextStatus = getNextContentStatus(normalizedAction);
      reviewComment = body.comment?.trim() || existing.reviewComment;
      successMessage =
        normalizedAction === 'publish'
          ? 'เผยแพร่บทเรียนเรียบร้อยแล้ว'
          : normalizedAction === 'archive'
            ? 'เก็บบทเรียนเข้าคลังเรียบร้อยแล้ว'
            : normalizedAction === 'approve'
              ? 'อนุมัติบทเรียนเรียบร้อยแล้ว'
              : normalizedAction === 'return'
                ? 'ส่งบทเรียนกลับเพื่อแก้ไขเรียบร้อยแล้ว'
                : normalizedAction === 'reject'
                  ? 'ปฏิเสธบทเรียนเรียบร้อยแล้ว'
                  : 'ส่งบทเรียนเพื่อตรวจสอบเรียบร้อยแล้ว';

      await db
        .update(onlineLessons)
        .set({
          status: nextStatus,
          submittedAt: normalizedAction === 'submit' ? new Date() : existing.submittedAt,
          submittedBy: normalizedAction === 'submit' ? session.user.id : existing.submittedBy,
          reviewedAt:
            normalizedAction === 'approve' ||
            normalizedAction === 'return' ||
            normalizedAction === 'reject'
              ? new Date()
              : existing.reviewedAt,
          reviewedBy:
            normalizedAction === 'approve' ||
            normalizedAction === 'return' ||
            normalizedAction === 'reject'
              ? session.user.id
              : existing.reviewedBy,
          approvedAt: normalizedAction === 'approve' ? new Date() : existing.approvedAt,
          approvedBy: normalizedAction === 'approve' ? session.user.id : existing.approvedBy,
          isPublished:
            normalizedAction === 'publish'
              ? true
              : normalizedAction === 'archive'
                ? false
                : existing.isPublished,
          publishedAt:
            normalizedAction === 'publish' ? existing.publishedAt ?? new Date() : existing.publishedAt,
          publishedBy: normalizedAction === 'publish' ? session.user.id : existing.publishedBy,
          reviewComment,
          updatedBy: session.user.id,
          updatedAt: new Date()
        })
        .where(and(eq(onlineLessons.id, id), eq(onlineLessons.organizationId, organization.id)));
    }

    const detailRow = await getOnlineLessonByIdForAccess({
      id,
      organizationId: organization.id,
      permissions: session.user.effectivePermissions
    });

    if (!detailRow) {
      throw new Error('ไม่พบข้อมูลบทเรียนออนไลน์หลังอัปเดต');
    }

    const serializedLesson = serializeOnlineLesson(detailRow);

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

    if (multipartAction === 'draft') {
      await logAuditEvent({
        organizationId: organization.id,
        userId: session.user.id,
        module: AUDIT_MODULE.ONLINE_LESSONS,
        action: AUDIT_ACTION.ONLINE_LESSON_DRAFT_SAVED,
        entityName: detailRow.title,
        entityId: detailRow.id,
        oldValue: toAuditValue(previousSerialized),
        newValue: toAuditValue(serializedLesson),
        ...requestMetadata
      });
    }

    if (existing.status !== 'pending_review' && nextStatus === 'pending_review') {
      await logAuditEvent({
        organizationId: organization.id,
        userId: session.user.id,
        module: AUDIT_MODULE.ONLINE_LESSONS,
        action: AUDIT_ACTION.ONLINE_LESSON_SUBMIT,
        entityName: detailRow.title,
        entityId: detailRow.id,
        oldValue: toAuditValue(previousSerialized),
        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: `มีบทเรียนใหม่รอตรวจสอบ: ${detailRow.title}`,
            message: 'มีการส่งบทเรียนออนไลน์เข้าสู่คิวตรวจสอบ กรุณาเปิดเพื่อตรวจสอบและอนุมัติ',
            type: 'CONTENT_SUBMITTED',
            referenceId: detailRow.id,
            referenceType: 'content_submission'
          })
        )
      );
    }

    if (existing.status !== 'approved' && nextStatus === 'approved') {
      await createContentWorkflowNotification({
        organizationId: organization.id,
        userId: detailRow.createdBy,
        title: `บทเรียนได้รับการอนุมัติ: ${detailRow.title}`,
        message: buildWorkflowMessage(reviewComment, 'บทเรียนของคุณผ่านการอนุมัติแล้ว'),
        type: 'CONTENT_APPROVED',
        referenceId: detailRow.id,
        referenceType: 'content_approval'
      });
    }

    if (existing.status !== 'returned' && nextStatus === 'returned') {
      await createContentWorkflowNotification({
        organizationId: organization.id,
        userId: detailRow.createdBy,
        title: `บทเรียนถูกส่งกลับแก้ไข: ${detailRow.title}`,
        message: buildWorkflowMessage(reviewComment, 'กรุณาปรับแก้และส่งตรวจสอบอีกครั้ง'),
        type: 'CONTENT_RETURNED',
        referenceId: detailRow.id,
        referenceType: 'content_approval'
      });
    }

    if (existing.status !== 'rejected' && nextStatus === 'rejected') {
      await createContentWorkflowNotification({
        organizationId: organization.id,
        userId: detailRow.createdBy,
        title: `บทเรียนไม่ผ่านการอนุมัติ: ${detailRow.title}`,
        message: buildWorkflowMessage(reviewComment, 'กรุณาปรับแก้ก่อนส่งใหม่'),
        type: 'CONTENT_REJECTED',
        referenceId: detailRow.id,
        referenceType: 'content_approval'
      });
    }

    if (existing.status !== 'published' && nextStatus === 'published') {
      await createContentWorkflowNotification({
        organizationId: organization.id,
        userId: detailRow.createdBy,
        title: `บทเรียนถูกเผยแพร่แล้ว: ${detailRow.title}`,
        message: 'บทเรียนของคุณถูกเผยแพร่เรียบร้อยแล้ว',
        type: 'CONTENT_PUBLISHED',
        referenceId: detailRow.id,
        referenceType: 'content_published'
      });
    }

    return NextResponse.json({
      success: true,
      time: new Date().toISOString(),
      message: successMessage,
      online_lesson: serializedLesson
    });
  } 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 update online lesson', error);
    return NextResponse.json({ message: getDatabaseErrorMessage(error) }, { status: 500 });
  }
}

export async function DELETE(
  _request: NextRequest,
  context: { params: Promise<{ id: string }> }
) {
  try {
    const { organization, session } = await requireOrganizationAccess();
    const { id: rawId } = await context.params;
    const id = parseId(rawId);

    const [existing] = await db
      .select()
      .from(onlineLessons)
      .where(and(eq(onlineLessons.id, id), eq(onlineLessons.organizationId, organization.id)))
      .limit(1);

    if (!existing) {
      return NextResponse.json({ message: 'ไม่พบบทเรียนออนไลน์' }, { status: 404 });
    }

    if (
      !canDeleteContent({
        module: 'online_lesson',
        permissions: session.user.effectivePermissions,
        status: existing.status,
        isOwner: existing.createdBy === session.user.id
      })
    ) {
      return NextResponse.json({ message: 'ไม่มีสิทธิ์ลบบทเรียนนี้' }, { status: 403 });
    }

    await db
      .delete(onlineLessons)
      .where(and(eq(onlineLessons.id, id), eq(onlineLessons.organizationId, organization.id)));

    for (const storageKey of [
      existing.videoStorageKey,
      existing.attachmentStorageKey,
      existing.thumbnailStorageKey
    ]) {
      if (storageKey) {
        await deleteStoredOnlineLessonAsset(storageKey);
      }
    }

    return NextResponse.json({
      success: true,
      message: 'ลบบทเรียนออนไลน์เรียบร้อยแล้ว'
    });
  } 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 delete online lesson', error);
    return NextResponse.json({ message: getDatabaseErrorMessage(error) }, { status: 500 });
  }
}
