import { z } from 'zod';

const expenseSchema = z.object({
  amount: z.number({ required_error: 'Amount is required' }).positive('Amount must be positive'),
  date: z.string({ required_error: 'Date is required' }).refine((val) => !isNaN(Date.parse(val)), {
    message: "Invalid date format",
  }),
  description: z.string().optional(),
  category: z.string({ required_error: 'Category is required' }).min(1, 'Category cannot be empty'),
  client_id: z.string({ required_error: 'Client ID is required' }).uuid('Invalid Client ID format'),
  billable_type: z.string().optional(),
  unit_price: z.number().optional(),
  quantity: z.number().optional(),
  address: z.string().optional(),
});

/**
 * Validates a single expense record against the schema.
 * @param {Object} record - The expense record to validate.
 * @returns {Object} - { valid: boolean, errors: string[] }
 */
export function validateExpenseRecord(record) {
  const result = expenseSchema.safeParse(record);
  if (result.success) {
    return { valid: true, errors: [] };
  } else {
    const formattedErrors = result.error.errors.map(err => `${err.path.join('.')}: ${err.message}`);
    return { valid: false, errors: formattedErrors };
  }
}

/**
 * Validates a list of expense records.
 * @param {Array} records - Array of expense objects.
 * @param {Set} validCategories - Set of valid category names (strings).
 * @param {string} targetClientId - (Optional) Ensure all records match this Client ID.
 * @returns {Object} - { valid: boolean, errors: Array<{row: number, messages: string[]}>, sanitizedRecords: Array }
 */
export function validateExpenseImport(records, validCategories, targetClientId = null) {
  const errors = [];
  const sanitizedRecords = [];

  records.forEach((record, index) => {
    const rowErrors = [];
    const rowNum = index + 1;

    // 1. Basic Schema Validation
    // Convert numeric strings to numbers for validation if necessary
    const processedRecord = {
      ...record,
      amount: typeof record.amount === 'string' ? parseFloat(record.amount) : record.amount,
      quantity: typeof record.quantity === 'string' ? parseFloat(record.quantity) : record.quantity,
      unit_price: typeof record.unit_price === 'string' ? parseFloat(record.unit_price) : record.unit_price,
    };

    const schemaResult = validateExpenseRecord(processedRecord);
    if (!schemaResult.valid) {
      rowErrors.push(...schemaResult.errors);
    }

    // 2. Business Logic: Category Validation
    if (processedRecord.category && validCategories.size > 0 && !validCategories.has(processedRecord.category)) {
      rowErrors.push(`Category '${processedRecord.category}' does not exist.`);
    }

    // 3. Security: Client ID Isolation
    if (targetClientId && processedRecord.client_id !== targetClientId) {
      rowErrors.push(`Client ID mismatch. Expected ${targetClientId}, got ${processedRecord.client_id}`);
    }

    // 4. SQL Injection Prevention / Sanitization (Basic)
    // Supabase handles parameterization, but we ensure strings don't contain dangerous control chars if needed.
    // Here we rely on Schema validation which ensures types.
    
    if (rowErrors.length > 0) {
      errors.push({ row: rowNum, messages: rowErrors });
    } else {
      sanitizedRecords.push(processedRecord);
    }
  });

  return {
    valid: errors.length === 0,
    errors,
    sanitizedRecords: errors.length === 0 ? sanitizedRecords : [] // All or nothing
  };
}