export const pktTypes: ReadonlyArray<PktEl['typ']> = [
  'txt',
  'num',
  'spin',
  'chk',
  'media',
  'date',
  'sign',
  'form',
  'ext',
  'gps',
  'lovibond',
  'list',
  'info',
  'time',
  'address'
] as const;

export type PktEl =
  | Txt
  | Numeric
  | Spinner
  | Checklist
  | Media
  | PktDate
  | Signature
  | Form<PktEl>
  | PktExternal
  | PktGps
  | PktLovibond
  | PktList
  | PktTime
  | PktAddress
  | Info;


export type EditorPktEl =
  | TxtEditor
  | NumericEditor
  | SpinnerEditor
  | ChecklistEditor
  | MediaEditor
  | PktDateEditor
  | SignatureEditor
  | FormEditor
  | PktGpsEditor
  | PktLovibondEditor
  | PktExternalEditor
  | PktListEditor
  | PktTimeEditor
  | PktAddressEditor
  | InfoEditor;

export type TxtEditor = Txt & EditorElProps;
export type NumericEditor = Numeric & EditorElProps;
export type MediaEditor = Media & EditorElProps;
export type PktDateEditor = PktDate & EditorElProps;
export type SignatureEditor = Signature & EditorElProps;
export type PktExternalEditor = PktExternal & EditorElProps;
export type PktGpsEditor = EditorElProps;
export type PktLovibondEditor = EditorElProps;
export type FormEditor = Form<EditorPktEl> & EditorElProps;
export type PktListEditor = PktList & EditorElProps;
export type PktTimeEditor = PktTime & EditorElProps;
export type PktAddressEditor = PktAddress & EditorElProps;
export type InfoEditor = Info & EditorElProps;


export interface SpinnerEditor extends Spinner, EditorElProps {
  items: SpinnerItemEditor[];
}
export type SpinnerItemEditor = {
  text: string;
  value: number | string;
  uuid: string;
};

export type ChecklistItemEditor = SpinnerItemEditor & {
  required?: boolean;
};

export interface ChecklistEditor extends Checklist, EditorElProps {
  items: ChecklistItemEditor[];
}

export interface EditorElProps {
  editing?: boolean;
  uuid: string;
}

interface PktElCommon {
  name?: string;
  required?: boolean;
  inf?: string; // Markdown
  isdescription?: boolean;
  addToTag?: boolean;
  movedya?: boolean;
  emailsend?: boolean;
  delete_in_days?: number;
  function?: string;
  unfolded?: boolean;
}

export interface Txt extends PktElCommon {
  typ: 'txt';
  hint?: string;
  default?:string;
  inptyp?: InpTyp;
  d?: { inp: string };
}
export interface Info extends PktElCommon {
  typ: 'info';
  hint?: string;
  inptyp?: InpTyp;
  d?: { inp: string };
}
export const inpTyps = [
  'time',
  'email',
  'url',
  'barcode',
  'datetime',
  'date',
  'timestamp',
] as const;
export type InpTyp = typeof inpTyps[number];

export interface Numeric extends PktElCommon {
  typ: 'num';
  hint?: string;
  max?: number;
  min?: number;
  d?: { inp: number };
}

export interface Spinner extends PktElCommon {
  typ: 'spin';
  items: SpinnerItem[];
  d?: {} | { inp: string };
  default?: any;
  en_timestamp?: boolean;
}
export type SpinnerItem = string | { text: string; value: number | string };
export type ChecklistItem =
  | string
  | { text: string; value: number | string; required?: boolean };

export interface Checklist extends PktElCommon {
  typ: 'chk';
  items: ChecklistItem[];
  d: { chk: string[] };
}

export interface Media extends PktElCommon {
  typ: 'media';
  max?: number;
  en_video?: boolean;
  d?: { pics: any[] };
}

export interface PktDate extends PktElCommon {
  typ: 'date';
  range: [number, number]; // Interval in days relative to today
  d: { inp: DateString };
  inptyp?: InpTyp;
}
export type DateString = string; // YYYY-MM-DD

export interface Signature extends PktElCommon {
  typ: 'sign';
  d: { filename: string };
}

export interface Form<ItemEl> extends PktElCommon {
  typ: 'form';
  items?: ItemEl[];
  tmp?: ItemEl[];
  max?: number;
  function?: string;
}

export interface PktExternal extends PktElCommon {
  typ: 'ext';
  'by.id': string;
  d: { resid: string };
}

export interface PktList extends PktElCommon {
  typ: 'list';
  listsrc?: string;
}
export interface PktGps extends PktElCommon {
  typ: 'gps';
  listsrc?: string;
}
export interface PktLovibond extends PktElCommon {
  typ: 'lovibond';
  listsrc?: string;
}
export interface PktTime extends PktElCommon {
  typ: 'time';
  d?: { inp: string }; // 'inp' is in the format 'hh:mm'
}

export interface PktAddress extends PktElCommon {
  typ: 'address';
  d?: {
    inp: string; // The address string from autocomplete
    lat?: number;
    lng?: number;
  };
}

function extract<T>(properties: Record<keyof T, true>) {
  return function<TActual extends T>(value: TActual) {
    let result = {} as T;
    for (const property of Object.keys(properties) as Array<keyof T>) {
      result[property] = value[property];
    }
    return result;
  };
}

export const extractPktCommon = extract<PktElCommon>({
  name: true,
  required: true,
  inf: true,
  isdescription: true,
  movedya: true,
  emailsend: true,
  delete_in_days: true,
  unfolded: true
});

export const extractEditorProps = extract<EditorElProps>({
  editing: true,
  uuid: true
});