export type OutputFormat = "xml" | "json";
export type cqStyleGroups = {
  readonly items: cqStyleGroup[];
}
export class CQStyleGroups {
  private items: CQStyleGroup[];

  constructor(items?: CQStyleGroup[]) {
    this.items = items || [];
  }

  addStyleGroup(styleGroup: CQStyleGroup): void {
    this.items.push(styleGroup);
  }

  format(output: OutputFormat = "xml", theme = {}) {
    if (output === "xml") {
      return {
        attributes: { "jcr:primaryType": "nt:unstructured", },
        ...this.formatItems(output, theme),
      }
    } else if (output === "json") {
      return {
        ["jcr:primaryType"]: "nt:unstructured",
        ...this.formatItems(output, theme),
      }
    }
  }

  private formatItems(output?: OutputFormat, theme?: object) {
    let formattedItems: { [key: string]: any } = {};
    this.items.forEach((item: CQStyleGroup | Function, i: number) => {
      if (typeof item === "function") {
        formattedItems[`item${i}`] = item(theme).format(output);
      } else if (typeof item.format === "function") formattedItems[`item${i}`] = item.format(output);
    });
    return formattedItems;
  }
}

export type cqStyleGroup = {
  label: string;
  allowMultiple?: boolean;
  styles?: CQStyle[];
}
export class CQStyleGroup {
  label: string;
  allowMultiple?: boolean;
  styles?: CQStyle[];

  constructor(settings: cqStyleGroup) {
    if (!settings) throw new Error(`No Settings were passed: ${settings}`)
    this.label = settings.label;
    this.allowMultiple = settings.allowMultiple || false;
    this.styles = settings.styles || [];
  }

  format(output: OutputFormat = "xml") {
    return {
      attributes: {
        ["jcr:primaryType"]: "nt:unstructured",
        ["cq:styleGroupLabel"]: this.label,
        ["cq:styleGroupMultiple"]: this.allowMultiple,
      },
      ["cq:styles"]: {
        attributes: {
          "jcr:primaryType": "nt:unstructured",
        },
        ...this.formatStyles(output)
      }
    }
  }

  private formatStyles(output?: OutputFormat) {
    let formattedStyles: { [key: string]: any } = {};
    this.styles.forEach((style, i) => formattedStyles[`item${i}`] = style.format(output))
    return formattedStyles;
  }

  addStyle(style: CQStyle): void {
    this.styles.push(style);
  }
}

export type cqStyle = {
  id: string | number;
  label: string | number;
  classes?: string | number;
  element?: string;
}
export class CQStyle {
  id: string | number;
  label: string | number;
  classes?: string | number;
  element?: string;

  constructor(settings: cqStyle) {
    if (!settings) throw new Error(`No Settings were passed: ${settings}`)
    this.id = settings.id;
    this.label = settings.label;
    this.classes = settings.classes ||  settings.id;
    if (settings.element) this.element = settings.element;
  }

  format(output: OutputFormat = "xml") {
    let attributes: { [key: string]: any } = {
      "jcr:primaryType": "nt:unstructured",
      "cq:styleId": this.id,
      "cq:styleLabel": this.label,
      "cq:styleClasses": this.classes,
    }
    if (this.element) attributes.element = this.element;

    if (output === "xml") attributes = { attributes: attributes };

    return attributes;
  }
}