/**
 * Shared contract for GET /api/dashboard/layer-data
 *
 * Both the API route and the frontend import this schema so TypeScript
 * catches any field-level mismatch at compile time — before it silently
 * drops all map points at runtime.
 */
import * as z from 'zod';

export const DerivedColumnOperationSchema = z.enum([
  'copy', 'add', 'subtract', 'multiply', 'divide', 'concat', 'formula',
]);

export const DerivedColumnConfigSchema = z.object({
  id: z.string(),
  name: z.string(),
  dataType: z.enum(['text', 'number', 'date']),
  mode: z.enum(['default', 'calculated']),
  defaultValue: z.union([z.string(), z.number(), z.null()]).optional(),
  defaultMode: z.enum(['empty-only', 'all']).optional(),
  calculation: z.object({
    operation: DerivedColumnOperationSchema,
    sourceColumns: z.array(z.string()),
    separator: z.string().optional(),
    decimalPlaces: z.number().int().min(0).max(10).optional(),
    formula: z.string().optional(),
  }).optional(),
});

export const SymbologyRuleSchema = z.object({
  value: z.string(),
  color: z.string(),
  icon: z.string().optional(),
  size: z.number().optional(),
  label: z.string().optional(),
});

export const LayerSymbologySchema = z.object({
  column: z.string(),
  rules: z.array(SymbologyRuleSchema),
  defaultColor: z.string(),
  defaultIcon: z.string().optional(),
  defaultSize: z.number().optional(),
  legendLabel: z.string().optional(),
});

export const PolygonStyleSchema = z.object({
  fillColor: z.string(),
  fillOpacity: z.number().min(0).max(1),
  strokeColor: z.string(),
  strokeWeight: z.number().min(0),
  legendLabel: z.string().optional(),
});

export const PolygonSymbologyRuleSchema = z.object({
  value: z.string(),
  fillColor: z.string(),
  label: z.string().optional(),
});

export const PolygonSymbologySchema = z.object({
  column: z.string(),
  rules: z.array(PolygonSymbologyRuleSchema),
  defaultFillColor: z.string(),
});

export const ClusterConfigSchema = z.object({
  enabled: z.boolean(),
  radius: z.number(),
  color: z.string(),
  maxZoom: z.number(),
  icon: z.string().optional(),
  minSize: z.number().optional(),
  maxSize: z.number().optional(),
  maxSizeCount: z.number().optional(),
  legendLabel: z.string().optional(),
  showInLegend: z.boolean().optional(),
});

export const PopupFieldConfigSchema = z.object({
  column: z.string(),
  label: z.string(),
  format: z.enum(['raw', 'number', 'percent', 'currency']),
  numericAgg: z.enum(['sum', 'min', 'max', 'avg', 'count']),
  textAgg: z.enum(['distinct', 'dominant']),
});

export const PopupConfigSchema = z.object({
  fields: z.array(PopupFieldConfigSchema),
  showOnHover: z.boolean(),
  showOnClick: z.boolean(),
});

/**
 * Exact shape returned by GET /api/dashboard/layer-data for each layer.
 * Any field the map renderer reads MUST be listed here.
 */
export const DashboardLayerDataItemSchema = z.object({
  id: z.string(),
  name: z.string(),
  color: z.string(),
  columns: z.array(z.string()),
  columnTypes: z.record(z.enum(['text', 'number', 'date'])),
  latColumn: z.string().optional(),
  lngColumn: z.string().optional(),
  geometryType: z.enum(['Point', 'LineString', 'MultiLineString', 'Polygon', 'MultiPolygon']).optional(),
  geometryColumn: z.string().optional(),
  visibility: z.boolean(),
  featureCount: z.number(),
  sourceType: z.string(),
  symbology: LayerSymbologySchema.optional(),
  polygonStyle: PolygonStyleSchema.optional(),
  polygonSymbology: PolygonSymbologySchema.optional(),
  clusterConfig: ClusterConfigSchema.optional(),
  popupConfig: PopupConfigSchema.optional(),
  derivedColumns: z.array(DerivedColumnConfigSchema).optional(),
  rows: z.array(z.record(z.union([z.string(), z.number(), z.boolean(), z.null()]))),
});

export type DashboardLayerDataItem = z.infer<typeof DashboardLayerDataItemSchema>;
export type PolygonStyle = z.infer<typeof PolygonStyleSchema>;
export type PopupFieldConfig = z.infer<typeof PopupFieldConfigSchema>;
export type PopupConfig = z.infer<typeof PopupConfigSchema>;
export type DerivedColumnConfig = z.infer<typeof DerivedColumnConfigSchema>;
