import { mutation } from "../_generated/server";
import { v } from "convex/values";

/**
 * Create a new job listing
 * Phase 8: Content, Careers, Real Estate, Analytics, Reviews
 */
export const createJob = mutation({
  args: {
    careerId: v.optional(v.string()),
    slug: v.string(),
    titleTranslations: v.any(),
    department: v.string(),
    departmentLabel: v.any(),
    locationTranslations: v.any(),
    contractType: v.optional(v.string()),
    level: v.optional(v.string()),
    responsibilities: v.optional(v.any()),
  },
  handler: async (ctx, args) => {
    const now = Date.now();
    const id = await ctx.db.insert("jobs", {
      careerId: args.careerId,
      slug: args.slug,
      titleTranslations: args.titleTranslations,
      department: args.department,
      departmentLabel: args.departmentLabel,
      locationTranslations: args.locationTranslations,
      contractType: args.contractType ?? "full_time",
      contractTypeLabel: {},
      level: args.level ?? "mid",
      levelLabel: {},
      compensationTranslations: {},
      responsibilities: args.responsibilities ?? [],
      status: "DRAFT",
      openingAt: now,
      createdAt: now,
      updatedAt: now,
    });
    return id;
  },
});

/**
 * Update job status (DRAFT -> OPEN -> PAUSED -> CLOSED -> ARCHIVED)
 * Phase 8: Content, Careers, Real Estate, Analytics, Reviews
 */
export const updateJobStatus = mutation({
  args: {
    id: v.id("jobs"),
    status: v.union(
      v.literal("DRAFT"),
      v.literal("OPEN"),
      v.literal("PAUSED"),
      v.literal("CLOSED"),
      v.literal("ARCHIVED"),
    ),
  },
  handler: async (ctx, args) => {
    const existing = await ctx.db.get(args.id);
    if (!existing) {
      throw new Error(`Job ${args.id} not found`);
    }
    await ctx.db.patch(args.id, {
      status: args.status,
      updatedAt: Date.now(),
    });
    return args.id;
  },
});

/**
 * Create a new job application
 * Phase 8: Content, Careers, Real Estate, Analytics, Reviews
 */
export const createApplication = mutation({
  args: {
    jobId: v.optional(v.string()),
    applicantName: v.string(),
    applicantEmail: v.string(),
    applicantPhone: v.string(),
    coverNote: v.optional(v.string()),
    cvPath: v.string(),
    cvFilename: v.string(),
    cvBytes: v.number(),
    submissionLanguage: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const now = Date.now();
    const id = await ctx.db.insert("job_applications", {
      jobId: args.jobId,
      applicantName: args.applicantName,
      applicantEmail: args.applicantEmail,
      applicantPhone: args.applicantPhone,
      coverNote: args.coverNote,
      cvBucket: "applications",
      cvPath: args.cvPath,
      cvFilename: args.cvFilename,
      cvBytes: args.cvBytes,
      cvMimeType: "application/pdf",
      submissionLanguage: args.submissionLanguage ?? "en",
      submittedAt: now,
      status: "NEW",
      createdAt: now,
    });
    return id;
  },
});

// ── WU-05/WU-14 gap-fill mutations ────────────────────────────────────────────

/**
 * Book an interview — creates booking record and marks token as used
 * Gap-fill for WU-05 data-source routing
 */
export const bookInterview = mutation({
  args: {
    applicationId: v.string(),
    jobId: v.string(),
    tokenId: v.string(),
    applicantName: v.string(),
    applicantEmail: v.string(),
    applicantPhone: v.optional(v.string()),
    preferredDate: v.string(),
    preferredTime: v.string(),
    timezone: v.string(),
    durationMinutes: v.number(),
    applicantNotes: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const now = Date.now();

    // Check for duplicate booking
    const existing = await ctx.db
      .query("interview_bookings")
      .withIndex("by_applicationId", (q) =>
        q.eq("applicationId", args.applicationId),
      )
      .filter((f) => f.and(f.neq(f.field("status"), "CANCELLED")))
      .first();

    if (existing) {
      throw new Error("DUPLICATE_BOOKING");
    }

    // Parse date/time into timestamps for Convex schema (number fields)
    const dateTs = new Date(args.preferredDate).getTime();
    const [hours, minutes] = args.preferredTime.split(":").map(Number);
    const timeTs = (hours * 60 + (minutes || 0)) * 60 * 1000;

    // Create booking
    const bookingId = await ctx.db.insert("interview_bookings", {
      applicationId: args.applicationId,
      jobId: args.jobId,
      tokenId: args.tokenId,
      applicantName: args.applicantName,
      applicantEmail: args.applicantEmail,
      applicantPhone: args.applicantPhone,
      preferredDate: dateTs,
      preferredTime: timeTs,
      timezone: args.timezone,
      durationMinutes: args.durationMinutes,
      applicantNotes: args.applicantNotes,
      status: "PENDING",
      createdAt: now,
      updatedAt: now,
    });

    // Mark token as used
    const tokenDoc = await ctx.db
      .query("interview_booking_tokens")
      .withIndex("by_token", (q) => q.eq("token", args.tokenId))
      .first();

    if (tokenDoc) {
      await ctx.db.patch(tokenDoc._id, {
        usedAt: now,
        updatedAt: now,
      });
    }

    return bookingId;
  },
});

/**
 * Cancel an interview booking
 * Gap-fill for WU-14 staff careers data-source routing
 */
export const cancelInterview = mutation({
  args: {
    bookingId: v.string(),
    cancelledBy: v.string(),
    cancellationReason: v.string(),
  },
  handler: async (ctx, args) => {
    const now = Date.now();

    // Find by prismaId or _id
    let booking = await ctx.db
      .query("interview_bookings")
      .filter((q) => q.eq(q.field("prismaId"), args.bookingId))
      .first();

    if (!booking) {
      try {
        booking = (await ctx.db.get(args.bookingId as any)) as typeof booking;
      } catch {
        // Not a valid Convex ID
      }
    }

    if (!booking) {
      throw new Error(`Interview booking ${args.bookingId} not found`);
    }

    if (booking.status === "CANCELLED") {
      throw new Error("Interview is already cancelled");
    }

    await ctx.db.patch(booking._id, {
      status: "CANCELLED",
      cancelledAt: now,
      cancelledBy: args.cancelledBy,
      cancellationReason: args.cancellationReason,
      updatedAt: now,
    });

    return booking._id;
  },
});

/**
 * Confirm an interview booking
 * Gap-fill for WU-14 staff careers data-source routing
 */
export const confirmInterview = mutation({
  args: {
    bookingId: v.string(),
    confirmedBy: v.string(),
  },
  handler: async (ctx, args) => {
    const now = Date.now();

    // Find by prismaId or _id
    let booking = await ctx.db
      .query("interview_bookings")
      .filter((q) => q.eq(q.field("prismaId"), args.bookingId))
      .first();

    if (!booking) {
      try {
        booking = (await ctx.db.get(args.bookingId as any)) as typeof booking;
      } catch {
        // Not a valid Convex ID
      }
    }

    if (!booking) {
      throw new Error(`Interview booking ${args.bookingId} not found`);
    }

    if (booking.status === "CONFIRMED") {
      throw new Error("Interview is already confirmed");
    }

    await ctx.db.patch(booking._id, {
      status: "CONFIRMED",
      confirmedAt: now,
      confirmedBy: args.confirmedBy,
      confirmedDate: booking.preferredDate,
      confirmedTime: booking.preferredTime,
      updatedAt: now,
    });

    return booking._id;
  },
});

/**
 * Add a note to a job application
 * Gap-fill for WU-14 staff careers data-source routing
 */
export const addApplicationNote = mutation({
  args: {
    applicationId: v.string(),
    staffId: v.string(),
    staffName: v.string(),
    noteText: v.string(),
  },
  handler: async (ctx, args) => {
    const now = Date.now();
    const noteId = await ctx.db.insert("application_notes", {
      applicationId: args.applicationId,
      staffId: args.staffId,
      staffName: args.staffName,
      noteText: args.noteText,
      createdAt: now,
      updatedAt: now,
    });
    return noteId;
  },
});

/**
 * Record that an interview invite was sent (creates a booking token)
 * Gap-fill for WU-14 staff careers data-source routing
 */
export const sendInterviewInvite = mutation({
  args: {
    token: v.string(),
    applicationId: v.string(),
    jobId: v.optional(v.string()),
    applicantEmail: v.string(),
    expiresAt: v.number(),
  },
  handler: async (ctx, args) => {
    const now = Date.now();
    const tokenId = await ctx.db.insert("interview_booking_tokens", {
      token: args.token,
      applicationId: args.applicationId,
      jobId: args.jobId,
      applicantEmail: args.applicantEmail,
      expiresAt: args.expiresAt,
      isRevoked: false,
      createdAt: now,
      updatedAt: now,
    });
    return tokenId;
  },
});

/**
 * Update an application's status and review fields
 * Gap-fill for WU-14 staff careers data-source routing
 */
export const updateApplicationStatus = mutation({
  args: {
    applicationId: v.string(),
    status: v.optional(v.string()),
    reviewedAt: v.optional(v.number()),
    reviewedBy: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    // Find by prismaId or _id
    let app = await ctx.db
      .query("job_applications")
      .filter((q) => q.eq(q.field("prismaId"), args.applicationId))
      .first();

    if (!app) {
      try {
        app = (await ctx.db.get(args.applicationId as any)) as typeof app;
      } catch {
        // Not a valid Convex ID
      }
    }

    if (!app) {
      throw new Error(`Application ${args.applicationId} not found`);
    }

    const patch: Record<string, unknown> = {};
    if (args.status !== undefined) patch.status = args.status;
    if (args.reviewedAt !== undefined) patch.reviewedAt = args.reviewedAt;
    if (args.reviewedBy !== undefined) patch.reviewedBy = args.reviewedBy;

    await ctx.db.patch(app._id, patch);
    return app._id;
  },
});
