import { ZodObject } from 'zod';
import { Flex, rem } from '@mantine/core';
import BooleanField from '@/components/ObjectForm/Fields/BooleanField/BooleanField';
import NumberField from '@/components/ObjectForm/Fields/NumberField/NumberField';
import StringField from '@/components/ObjectForm/Fields/StringField/StringField';

type EditProps<T> = {
  object: T;
  onChange: (item: T) => void;
};
type CreateProps<T> = {
  onCreate: (item: T) => void;
};
type SchemaLabels<S extends ZodObject<any>> = Partial<Record<keyof S['shape'], string>>;
type RestProps<S extends ZodObject<any>> =
  | {
      schema: S;
      labels?: SchemaLabels<S>;
      excludeKeys?: (keyof S['shape'])[];
      includeKeys?: never;
    }
  | {
      schema: S;
      labels?: SchemaLabels<S>;
      includeKeys?: (keyof S['shape'])[];
      excludeKeys?: never;
    };

type Props<ObjectType, ObjectSchema extends ZodObject> = (
  | EditProps<ObjectType>
  | CreateProps<ObjectType>
) &
  RestProps<ObjectSchema>;

const RenderField = (key: string, value: any, label?: string) => {
  const getField = () => {
    switch (value.type) {
      case 'string':
        return <StringField label={label ? label : key} />;
      case 'number':
        return <NumberField label={label ? label : key} />;
      case 'boolean':
        return <BooleanField label={label ? label : key} />;
      default:
        return <></>;
    }
  };
  return <div key={key}>{getField()}</div>;
};

function ObjectForm<ObjectType, ObjectSchema extends ZodObject<any, any>>(
  props: Props<ObjectType, ObjectSchema>
) {
  const processKeyValue = (key: string, val: any) => {
    const keyTyped = key as keyof typeof props.schema.shape;
    if (props.excludeKeys && props.excludeKeys.includes(keyTyped)) {
      return <></>;
    }

    if (props.includeKeys && !props.includeKeys.includes(keyTyped)) {
      return <></>;
    }
    const label = props.labels ? props.labels[keyTyped] : undefined;
    return RenderField(key, val, label);
  };
  return (
    <Flex gap={rem(10)} direction="column">
      {Object.entries(props.schema.shape).map(([key, val]) => {
        return processKeyValue(key, val);
      })}
    </Flex>
  );
}
export default ObjectForm;
