import * as z from 'zod';
import { isValidDateOnlyString } from '@/features/crm/shared/hot-project';

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));
}

function optionalDateOnly(message: string) {
  return z
    .string()
    .optional()
    .nullable()
    .refine((value) => !value || isValidDateOnlyString(value), message);
}

function requiredDateOnly(message: string) {
  return z
    .string()
    .min(1, message)
    .refine((value) => isValidDateOnlyString(value), message);
}

export const quotationSchema = z.object({
  opportunityId: z.string().optional().nullable(),
  customerId: z.string().min(1, 'Please select customer'),
  contactId: z.string().optional().nullable(),
  quotationDate: requiredDateOnly('Quotation date must be YYYY-MM-DD'),
  validUntil: optionalDateOnly('Valid until date must be YYYY-MM-DD'),
  quotationType: z.string().min(1, 'Please select 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 currency'),
  exchangeRate: coerceOptionalNumber('Exchange rate must be number'),
  status: z.string().min(1, 'Please select status'),
  chancePercent: coerceOptionalNumber('Chance percent must be number').refine(
    (value) => value === undefined || (value >= 0 && value <= 100),
    'Chance percent must be between 0 and 100'
  ),
  projectCloseDate: optionalDateOnly('Project close date must be YYYY-MM-DD'),
  deliveryDate: optionalDateOnly('Delivery date must be YYYY-MM-DD'),
  isHotProject: z.boolean().default(false),
  hotProjectAutoSuggested: z.boolean().default(false),
  hotProjectManuallyOverridden: 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 number').refine(
    (value) => value === undefined || value >= 0,
    'Discount must be 0 or greater'
  ),
  discountType: z.string().optional().nullable(),
  taxRate: coerceOptionalNumber('Tax rate must be number').refine(
    (value) => value === undefined || value >= 0,
    'Tax rate must be 0 or greater'
  ),
  sentVia: z.string().optional().nullable(),
  revisionRemark: z.string().optional().nullable(),
  isActive: z.boolean().default(true),
  projectParties: z
    .array(
      z.object({
        customerId: z.string().min(1, 'Please select customer'),
        role: z.string().min(1, 'Please select 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 product type'),
  description: z.string().min(2, 'Description must be at least 2 characters'),
  quantity: coerceRequiredNumber('Quantity must be number').refine(
    (value) => value > 0,
    'Quantity must be greater than 0'
  ),
  unit: z.string().optional(),
  unitPrice: coerceRequiredNumber('Unit price must be number').refine(
    (value) => value >= 0,
    'Unit price must be 0 or greater'
  ),
  discount: coerceOptionalNumber('Discount must be number').refine(
    (value) => value === undefined || value >= 0,
    'Discount must be 0 or greater'
  ),
  discountType: z.string().nullable().optional(),
  taxRate: coerceOptionalNumber('Tax rate must be number').refine(
    (value) => value === undefined || value >= 0,
    'Tax rate must be 0 or greater'
  ),
  notes: z.string().optional(),
  sortOrder: coerceOptionalNumber('Sort order must be number')
});

export const quotationCustomerSchema = z.object({
  customerId: z.string().min(1, 'Please select customer'),
  role: z.string().min(1, 'Please select 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 topic type'),
  title: z.string().min(2, 'Title must be at least 2 characters'),
  sortOrder: coerceOptionalNumber('Sort order must be number'),
  items: z
    .array(
      z.object({
        id: z.string().optional(),
        content: z.string().min(1, 'Topic item content required'),
        sortOrder: coerceOptionalNumber('Sort order must be number')
      })
    )
    .min(1, 'At least one topic item required')
});

export const quotationFollowupSchema = z.object({
  id: z.string().optional(),
  followupDate: requiredDateOnly('Follow-up date must be YYYY-MM-DD'),
  followupType: z.string().min(1, 'Please select follow-up type'),
  contactId: z.string().optional().nullable(),
  outcome: z.string().optional(),
  notes: z.string().optional(),
  nextFollowupDate: optionalDateOnly('Next follow-up date must be YYYY-MM-DD'),
  nextAction: z.string().optional()
});

export const quotationAttachmentSchema = z.object({
  id: z.string().optional(),
  fileName: z.string().min(1, 'Stored file name required'),
  originalFileName: z.string().min(1, 'Original file name required'),
  filePath: z.string().min(1, 'File path required'),
  fileSize: coerceOptionalNumber('File size must be 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>;
