import * as z from 'zod';

function coerceOptionalNumber(message: string) {
  return z.preprocess((value) => {
    if (value === '' || value === null || value === undefined) {
      return undefined;
    }

    if (typeof value === 'number') {
      return value;
    }

    if (typeof value === 'string') {
      const trimmed = value.trim();

      if (!trimmed) {
        return undefined;
      }

      return Number(trimmed);
    }

    return value;
  }, z.number().refine((value) => !Number.isNaN(value), message).optional());
}

function coerceRequiredNumber(message: string) {
  return z.preprocess((value) => {
    if (typeof value === 'number') {
      return value;
    }

    if (typeof value === 'string') {
      return Number(value.trim());
    }

    return value;
  }, z.number().refine((value) => !Number.isNaN(value), message));
}

export const quotationSchema = z.object({
  enquiryId: z.string().optional().nullable(),
  customerId: z.string().min(1, 'Please select a customer'),
  contactId: z.string().optional().nullable(),
  quotationDate: z.string().min(1, 'Quotation date is required'),
  validUntil: z.string().optional().nullable(),
  quotationType: z.string().min(1, 'Please select a quotation type'),
  projectName: z.string().optional(),
  projectLocation: z.string().optional(),
  attention: z.string().optional(),
  branchId: z.string().optional().nullable(),
  currency: z.string().min(1, 'Please select a currency'),
  exchangeRate: coerceOptionalNumber('Exchange rate must be a number'),
  status: z.string().min(1, 'Please select a status'),
  chancePercent: coerceOptionalNumber('Chance percent must be a number')
    .refine(
      (value) => value === undefined || (value >= 0 && value <= 100),
      'Chance percent must be between 0 and 100'
    ),
  isHotProject: z.boolean().default(false),
  competitor: z.string().optional(),
  reference: z.string().optional(),
  notes: z.string().optional(),
  salesmanId: z.string().optional().nullable(),
  discount: coerceOptionalNumber('Discount must be a number'),
  discountType: z.string().optional().nullable(),
  taxRate: coerceOptionalNumber('Tax rate must be a number'),
  isActive: z.boolean().default(true),
  sentVia: z.string().optional().nullable(),
  revisionRemark: z.string().optional().nullable(),
  projectParties: z
    .array(
      z.object({
        customerId: z.string().min(1, 'Please select a customer'),
        role: z.string().min(1, 'Please select a role'),
        isPrimary: z.boolean().default(false).optional(),
        remark: z.string().nullable().optional()
      })
    )
    .optional()
});

export const quotationItemSchema = z.object({
  productType: z.string().min(1, 'Please select a product type'),
  description: z.string().min(2, 'Description must be at least 2 characters'),
  quantity: coerceRequiredNumber('Quantity must be a number').refine(
    (value) => value > 0,
    'Quantity must be greater than 0'
  ),
  unit: z.string().optional(),
  unitPrice: coerceRequiredNumber('Unit price must be a number').refine(
    (value) => value >= 0,
    'Unit price must be 0 or greater'
  ),
  discount: coerceOptionalNumber('Discount must be a number').refine(
    (value) => value === undefined || value >= 0,
    'Discount must be 0 or greater'
  ),
  discountType: z.string().nullable().optional(),
  taxRate: coerceOptionalNumber('Tax rate must be a number').refine(
    (value) => value === undefined || value >= 0,
    'Tax rate must be 0 or greater'
  ),
  notes: z.string().optional(),
  sortOrder: coerceOptionalNumber('Sort order must be a number')
});

export const quotationCustomerSchema = z.object({
  customerId: z.string().min(1, 'Please select a customer'),
  role: z.string().min(1, 'Please select a role'),
  isPrimary: z.boolean().default(false),
  remark: z.string().nullable().optional()
});

export const quotationTopicSchema = z.object({
  id: z.string().optional(),
  topicType: z.string().min(1, 'Please select a topic type'),
  title: z.string().min(2, 'Title must be at least 2 characters'),
  sortOrder: coerceOptionalNumber('Sort order must be a number'),
  items: z
    .array(
      z.object({
        id: z.string().optional(),
        content: z.string().min(1, 'Topic item content is required'),
        sortOrder: coerceOptionalNumber('Sort order must be a number')
      })
    )
    .min(1, 'At least one topic item is required')
});

export const quotationFollowupSchema = z.object({
  id: z.string().optional(),
  followupDate: z.string().min(1, 'Follow-up date is required'),
  followupType: z.string().min(1, 'Please select a follow-up type'),
  contactId: z.string().optional().nullable(),
  outcome: z.string().optional(),
  notes: z.string().optional(),
  nextFollowupDate: z.string().optional().nullable(),
  nextAction: z.string().optional()
});

export const quotationAttachmentSchema = z.object({
  id: z.string().optional(),
  fileName: z.string().min(1, 'Stored file name is required'),
  originalFileName: z.string().min(1, 'Original file name is required'),
  filePath: z.string().min(1, 'File path is required'),
  fileSize: coerceOptionalNumber('File size must be a number'),
  fileType: z.string().nullable().optional(),
  description: z.string().optional()
});

export const quotationRevisionSchema = z.object({
  revisionRemark: z.string().optional()
});

export type QuotationFormValues = z.input<typeof quotationSchema>;
export type QuotationItemFormValues = z.input<typeof quotationItemSchema>;
export type QuotationCustomerFormValues = z.input<typeof quotationCustomerSchema>;
export type QuotationTopicFormValues = z.input<typeof quotationTopicSchema>;
export type QuotationFollowupFormValues = z.input<typeof quotationFollowupSchema>;
export type QuotationAttachmentFormValues = z.input<typeof quotationAttachmentSchema>;
