import { defineTable } from "convex/server";
import { v } from "convex/values";

// ── Enums ──────────────────────────────────────────────────────────────

export const quotationStatusValidator = v.union(
  v.literal("DRAFT"),
  v.literal("SENT"),
  v.literal("VIEWED"),
  v.literal("ACCEPTED"),
  v.literal("DECLINED"),
  v.literal("EXPIRED"),
  v.literal("CANCELLED"),
);

export const dealStageValidator = v.union(
  v.literal("LEAD"),
  v.literal("QUALIFIED"),
  v.literal("PROPOSAL"),
  v.literal("NEGOTIATION"),
  v.literal("CLOSED_WON"),
  v.literal("CLOSED_LOST"),
);

export const recurringFrequencyValidator = v.union(
  v.literal("MONTHLY"),
  v.literal("QUARTERLY"),
  v.literal("SEMI_ANNUAL"),
  v.literal("ANNUAL"),
  v.literal("CUSTOM"),
);

export const recurringStatusValidator = v.union(
  v.literal("ACTIVE"),
  v.literal("PAUSED"),
  v.literal("CANCELLED"),
  v.literal("COMPLETED"),
);

export const quotationPaymentStatusValidator = v.union(
  v.literal("UNPAID"),
  v.literal("PARTIAL"),
  v.literal("PAID"),
  v.literal("OVERDUE"),
);

export const paymentMethodValidator = v.union(
  v.literal("STRIPE"),
  v.literal("MANUAL_CASH"),
  v.literal("MANUAL_BANK_TRANSFER"),
  v.literal("MANUAL_CHECK"),
  v.literal("MANUAL_OTHER"),
);

export const penaltyTypeValidator = v.union(
  v.literal("PERCENTAGE"),
  v.literal("FLAT"),
);

// ── Tables ─────────────────────────────────────────────────────────────

export const quotationTables = {
  quotations: defineTable({
    prismaId: v.optional(v.string()),
    userId: v.string(),
    customerId: v.optional(v.string()),
    quotationNumber: v.string(),
    title: v.string(),
    notes: v.optional(v.string()),
    status: quotationStatusValidator,
    currency: v.string(),
    subtotal: v.number(),
    taxRate: v.number(),
    taxAmount: v.number(),
    discountRate: v.number(),
    discountAmount: v.number(),
    total: v.number(),
    validUntil: v.optional(v.number()),
    sentAt: v.optional(v.number()),
    viewedAt: v.optional(v.number()),
    respondedAt: v.optional(v.number()),
    metadata: v.optional(v.any()),
    createdAt: v.number(),
    updatedAt: v.number(),
    paymentStatus: quotationPaymentStatusValidator,
    amountPaid: v.number(),
    dueDate: v.optional(v.number()),
    paidAt: v.optional(v.number()),
    stripeCheckoutUrl: v.optional(v.string()),
    stripeSessionId: v.optional(v.string()),
    recurringTemplateId: v.optional(v.string()),
    recurringSequence: v.optional(v.number()),
    portalToken: v.optional(v.string()),
    penaltyAmount: v.number(),
    penaltyAppliedAt: v.optional(v.number()),
  })
    .index("by_userId", ["userId"])
    .index("by_userId_status", ["userId", "status"])
    .index("by_customerId", ["customerId"])
    .index("by_createdAt", ["createdAt"])
    .index("by_status", ["status"])
    .index("by_paymentStatus", ["paymentStatus"])
    .index("by_dueDate", ["dueDate"])
    .index("by_portalToken", ["portalToken"])
    .index("by_userId_paymentStatus", ["userId", "paymentStatus"])
    .index("by_dueDate_paymentStatus", ["dueDate", "paymentStatus"])
    .index("by_recurringTemplateId", ["recurringTemplateId"])
    .index("by_quotationNumber", ["quotationNumber"]),

  quotation_items: defineTable({
    prismaId: v.optional(v.string()),
    quotationId: v.string(),
    description: v.string(),
    quantity: v.number(),
    unitPrice: v.number(),
    total: v.number(),
    sortOrder: v.number(),
    createdAt: v.number(),
    updatedAt: v.number(),
  })
    .index("by_quotationId", ["quotationId"])
    .index("by_quotationId_sortOrder", ["quotationId", "sortOrder"]),

  quotation_payments: defineTable({
    prismaId: v.optional(v.string()),
    quotationId: v.string(),
    amount: v.number(),
    currency: v.string(),
    method: paymentMethodValidator,
    stripePaymentIntentId: v.optional(v.string()),
    reference: v.optional(v.string()),
    manualNotes: v.optional(v.string()),
    recordedBy: v.optional(v.string()),
    paidAt: v.number(),
    createdAt: v.number(),
  })
    .index("by_quotationId", ["quotationId"])
    .index("by_quotationId_paidAt", ["quotationId", "paidAt"])
    .index("by_stripePaymentIntentId", ["stripePaymentIntentId"]),

  quotation_penalties: defineTable({
    prismaId: v.optional(v.string()),
    quotationId: v.string(),
    amount: v.number(),
    penaltyType: penaltyTypeValidator,
    rate: v.optional(v.number()),
    flatAmount: v.optional(v.number()),
    isCompound: v.boolean(),
    daysOverdue: v.number(),
    appliedAt: v.number(),
    createdAt: v.number(),
  })
    .index("by_quotationId", ["quotationId"])
    .index("by_quotationId_appliedAt", ["quotationId", "appliedAt"]),

  quotation_reminders: defineTable({
    prismaId: v.optional(v.string()),
    quotationId: v.string(),
    channel: v.string(),
    trigger: v.string(),
    dayOffset: v.number(),
    sentAt: v.number(),
    emailSent: v.boolean(),
    whatsappSent: v.boolean(),
    error: v.optional(v.string()),
    createdAt: v.number(),
  })
    .index("by_quotationId", ["quotationId"])
    .index("by_sentAt", ["sentAt"])
    .index("by_quotationId_trigger_dayOffset", [
      "quotationId",
      "trigger",
      "dayOffset",
    ]),

  quotation_settings: defineTable({
    prismaId: v.optional(v.string()),
    userId: v.string(),
    defaultCurrency: v.string(),
    defaultTaxRate: v.number(),
    defaultPaymentTerms: v.number(),
    defaultValidDays: v.number(),
    penaltyEnabled: v.boolean(),
    penaltyType: penaltyTypeValidator,
    penaltyRate: v.number(),
    penaltyGraceDays: v.number(),
    penaltyCompound: v.boolean(),
    penaltyMaxAmount: v.optional(v.number()),
    penaltyFrequencyDays: v.number(),
    reminderEnabled: v.boolean(),
    reminderChannel: v.string(),
    reminderSchedule: v.any(),
    companyName: v.optional(v.string()),
    companyLogo: v.optional(v.string()),
    footerText: v.optional(v.string()),
    createdAt: v.number(),
    updatedAt: v.number(),
  }).index("by_userId", ["userId"]),

  quotation_recurring_templates: defineTable({
    prismaId: v.optional(v.string()),
    userId: v.string(),
    customerId: v.optional(v.string()),
    title: v.string(),
    notes: v.optional(v.string()),
    currency: v.string(),
    taxRate: v.number(),
    discountRate: v.number(),
    validDays: v.number(),
    paymentDueDays: v.number(),
    frequency: recurringFrequencyValidator,
    customIntervalDays: v.optional(v.number()),
    status: recurringStatusValidator,
    startDate: v.number(),
    nextRunDate: v.number(),
    endDate: v.optional(v.number()),
    maxOccurrences: v.optional(v.number()),
    occurrenceCount: v.number(),
    autoSend: v.boolean(),
    metadata: v.optional(v.any()),
    createdAt: v.number(),
    updatedAt: v.number(),
  })
    .index("by_userId", ["userId"])
    .index("by_userId_status", ["userId", "status"])
    .index("by_customerId", ["customerId"])
    .index("by_nextRunDate_status", ["nextRunDate", "status"])
    .index("by_status", ["status"]),

  quotation_recurring_template_items: defineTable({
    prismaId: v.optional(v.string()),
    templateId: v.string(),
    description: v.string(),
    quantity: v.number(),
    unitPrice: v.number(),
    total: v.number(),
    sortOrder: v.number(),
    createdAt: v.number(),
    updatedAt: v.number(),
  })
    .index("by_templateId", ["templateId"])
    .index("by_templateId_sortOrder", ["templateId", "sortOrder"]),

  deals: defineTable({
    prismaId: v.optional(v.string()),
    userId: v.string(),
    customerId: v.optional(v.string()),
    quotationId: v.optional(v.string()),
    title: v.string(),
    value: v.number(),
    currency: v.string(),
    stage: dealStageValidator,
    probability: v.number(),
    expectedCloseDate: v.optional(v.number()),
    closedAt: v.optional(v.number()),
    lostReason: v.optional(v.string()),
    notes: v.optional(v.string()),
    metadata: v.optional(v.any()),
    createdAt: v.number(),
    updatedAt: v.number(),
  })
    .index("by_userId", ["userId"])
    .index("by_userId_stage", ["userId", "stage"])
    .index("by_customerId", ["customerId"])
    .index("by_quotationId", ["quotationId"])
    .index("by_stage", ["stage"])
    .index("by_createdAt", ["createdAt"]),
};
