<template>
  <div class="blocks-grid-wrapper">
    <data-block
      v-show="isSectionVisible(mappedData)"
      :form-data="mappedData"
      :loading="mappedData.loading"
      :border="mappedData.border"
      :bolder="mappedData.bolder"
      :class="mappedData.class"
      :no-padding="mappedData.noPadding"
      :caps-title="mappedData.capsTitle"
      :background="mappedData.background"
    >
      <div
        v-for="(row, r) in mappedData.rows"
        :key="r"
        :style="
          gridTemplateColumns(row) &&
          `grid-template-columns:${gridTemplateColumns(row)};`
        "
        :class="row.label && r === 0 && 'q-pt-sm'"
        class="blocks-grid"
      >
        <data-blocks-grid
          v-for="(col, i) in row.children"
          :key="i"
          :data="col"
        />
      </div>
    </data-block>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import DataBlock from '@components/cards/statements/components/dataBlock.vue';

export interface DataBlockProps {
  bolder?: boolean;
  border?: boolean;
  noPadding?: boolean;
  capsTitle?: boolean;
  background?: string;
  loading?: boolean;
}

export interface FormDataSectionProps extends DataBlockProps {
  children?: Array<FormDataSectionProps>;
  label?: string;
  value?: string | number;
  icon?: string;
  class?: string;
  style?: string;
  columns?: number;
  size?: number;
  rows?: Array<FormDataSectionProps>;
  hide?: boolean;
  hideEmptyChildren?: boolean;
  hideIfEmpty?: boolean;
  growMode?: boolean;
}

@Component({
  name: 'DataBlocksGrid',
  components: {
    DataBlock,
    DataBlocksGrid,
  },
})
export default class DataBlocksGrid extends Vue {
  @Prop({
    default: () => ({
      children: [],
    }),
  })
  readonly data: FormDataSectionProps;

  get mappedData(): FormDataSectionProps {
    const data = {
      size: 1,
      children: [],
      class: '',
      hideEmptyChildren: true,
      hideIfEmpty: true,
      rows: this.divideChildSectionsIntoRows(this.data),
      ...this.data,
    };
    return data;
  }

  gridTemplateColumns(row: FormDataSectionProps): string {
    return (
      row?.children?.reduce(
        (acc, section) => acc + `${section?.size ?? 1}fr `,
        ''
      ) ?? ''
    );
  }

  isSectionEmpty(section: FormDataSectionProps): boolean {
    if (section.value) return false;
    if (!section?.children?.length) return true;
    if (!section.hideEmptyChildren) return false;
    const allChildrenAreEmpty = !section.children.some(
      (child) => !this.isSectionEmpty(child)
    );
    return allChildrenAreEmpty;
  }

  isSectionVisible(section: FormDataSectionProps): boolean {
    if (section.hide) return false;
    if (!section.hideIfEmpty) return true;
    return !this.isSectionEmpty(section);
  }

  divideChildSectionsIntoRows({
    children = [],
    hideEmptyChildren = true,
    columns = 1,
    growMode = false,
  }: FormDataSectionProps): Array<FormDataSectionProps> {
    const rows: Array<Array<FormDataSectionProps>> = [];
    let usedColumnsAmount = 0;

    const visibleChildren = children
      .map((child) => ({
        hideIfEmpty: child.hideIfEmpty ?? hideEmptyChildren,
        ...child,
      }))
      .filter(this.isSectionVisible);

    visibleChildren.forEach((child) => {
      if (columns < usedColumnsAmount + (child?.size ?? 1)) {
        usedColumnsAmount = child?.size ?? 1;
        rows.push([child]);
        return;
      }

      if (!rows[rows.length - 1]) rows.push([]);
      usedColumnsAmount += child.size ?? 1;
      rows[rows.length - 1].push(child);
    });

    const rowsWithMocks = rows.map((row) => {
      const usedColumns = row.reduce((acc, col) => acc + (col?.size ?? 1), 0);
      if (usedColumns < columns) {
        const unusedColumns = columns - usedColumns;
        if (growMode) {
          const lastChild = row[row.length - 1];
          if (lastChild.size) {
            lastChild.size += unusedColumns;
          }
          return row;
        }

        return [...row, { size: columns - usedColumns, hide: true }];
      }

      return row;
    });
    return rowsWithMocks.map((row) => ({
      children: row,
      class: 'q-pa-none',
      background: 'transparent',
      border: true,
    }));
  }
}
</script>

<style lang="scss" scoped>
.blocks-grid {
  display: grid;
  gap: 4px;
  grid-auto-columns: 1fr;
  & + .blocks-grid {
    margin-top: 4px;
  }
}
::v-deep {
  .row + .row {
    margin-top: 4px;
  }
}
</style>
