import React, { forwardRef } from 'react';
import styled, { css } from 'styled-components';

import { Box as Div, Stop } from 'src/components/abstract/boxes';
import { outputFunctions } from 'src/components/abstract/system';

/*
  TODO

    flow
    - create Flow component
    - props for flex-direction: row, column, row-reverse, column-reverse

    grid
    - create Grid component
*/

export const baseStyles = css`
  /*
    MULTI-COLUMN GRID

    1. create new stacking context; see issues https://caniuse.com/#feat=multicolumn
    2. see column/section/page fragmentation https://www.smashingmagazine.com/2019/02/css-fragmentation/
    3. this prop has bad cross-browser consistency so it's being nullified
    4. don't break inside; treat as blocks
    5. make background-color reveal gaps
  */

  .McolEl-base,
  .McolGridEl-base {
    column-fill: balance;
    column-width: auto;
    column-count: var(--column-count);
    column-gap: var(--column-gap);
    perspective: 1; /* 1 */
    & > * {
      display: block;
      box-decoration-break: clone; /* 2 */
      column-span: none; /* 3 */
      break-before: auto;
      break-after: auto;
      orphans: 2;
      widows: 2;
    }
    /* & > * {
      --column-span: calc(var(--column-span-proxy, var(--column-count)) / var(--multi-column-count, 1));
      --column-count: calc(
        var(--column-count-proxy, var(--column-count)) / var(--multi-column-count, 1)
      );
    } */
  }
  .McolGridEl-base {
    margin: calc(var(--row-gap) / -2) 0 !important;
    & > * {
      break-inside: avoid; /* 4 */
      background-clip: content-box; /* 5 */
      padding: calc(var(--row-gap) / 2) 0 !important;
    }
  }

  /*
    FLEX-BOX GRID

    1. prevent text forcing width https://css-tricks.com/flexbox-truncated-text/
    2. prevent collapse (might be only for float-based though)
    3. so gutters remain clear
    4. prevents cells wider than grid (maybe don't do this)
   */

  .FlowEl-base,
  .FlowGridEl-base {
    display: flex !important;
    flex-flow: row wrap;
    width: calc(100% + var(--column-gap));
    margin: calc(var(--row-gap) / -2) calc(var(--column-gap) / -2);
    & > * {
      flex: 0 0 auto;
      width: auto;
      min-width: 0%; /* 1 */
      /* max-width: 100%; */ /* 4 */
      min-height: 1px; /* 2 */
      background-clip: content-box; /* 3 */
      padding: calc(var(--row-gap) / 2) calc(var(--column-gap) / 2);
    }
  }

  .FlowGridEl-base {
    & > * {
      /* TODO: create a function for computing flow-span */
      /* padding: calc(var(--row-gap) / 2) calc(var(--column-gap) / 2); */
      width: calc(99.99999% * var(--column-span, var(--column-count)) / var(--column-count));
      /* margin-left: calc(99.99999% * var(--column-push-left, 0) / var(--column-count));
      margin-right: calc(99.99999% * var(--column-push-right, 0) / var(--column-count)); */
    }
  }

  /*
    GRID GRID

    1. similar to 'min-width: 0%' rule for flexbox https://css-tricks.com/flexbox-truncated-text/
    2. to reset any 'span' related widths

  */

  .GridEl-base {
    display: grid !important;
    grid-gap: var(--row-gap) var(--column-gap);
    grid-template-columns: repeat(var(--column-span, var(--column-count)), minmax(0%, 1fr)); /* 1 */
    grid-template-rows: repeat(var(--row-span, var(--row-count, 1)), max-content);
    /* &.row {
      grid-auto-flow: row;
    }
    &.col {
      grid-auto-flow: column;
    }
    &.row-reverse {
      grid-auto-flow: row-reverse;
    }
    &.col-reverse {
      grid-auto-flow: column-reverse;
    } */
    & > * {
      width: initial !important; /* 2 */
      grid-column: span var(--column-span, 1) / span var(--column-span, 1);
      grid-row: span var(--row-span, 1) / span var(--row-span, 1);
    }
  }

  /* make the following props *non-cascading* */
  * {
    --column-span: initial;
    /* --column-push-left: initial;
    --column-push-right: initial; */
  }
`;

/* eslint-disable prettier/prettier */

// const Stop = styled(Div).attrs(({py, ...rest}) => ({...rest, py: py||0.1}))``;

export const McolEl = styled.div.attrs({
  className: 'McolEl-base',
}).withConfig({
  shouldForwardProp: (key) => !['gapY', 'gapX','cols'].includes(key),
})`${({ gapX, cols }) => [
  cols && outputFunctions.cols(cols),
  gapX && outputFunctions.gapX(gapX),
]}`;

export const McolGridEl = styled(McolEl).attrs({
  className: 'McolGridEl-base',
}).withConfig({
  shouldForwardProp: (key) => !['gapY', 'gapX','cols'].includes(key),
})`${({ gapY }) => [
  gapY && outputFunctions.gapY(gapY),
]}`;

/* eslint-enable prettier/prettier */

export const McolGrid = forwardRef(
  ({ as, gap, gapY = gap, gapX = gap, span, cols = span, children, ...restProps }, ref) => {
    return (
      <Stop {...{ span, ...restProps }}>
        <McolGridEl ref={ref} forwardedAs={as} {...{ gapY, gapX, cols }}>
          {children}
        </McolGridEl>
      </Stop>
    );
  },
);
McolGrid.displayName = 'McolGrid';

/* eslint-disable prettier/prettier */

export const FlowEl = styled(Div).attrs({
  className: 'FlowEl-base',
}).withConfig({
  shouldForwardProp: (key) => ![].includes(key),
})`${({ gapX, gapY }) => [
  gapX && outputFunctions.gapX(gapX),
  gapY && outputFunctions.gapY(gapY),
]}`;

export const FlowGridEl = styled(FlowEl).attrs({
  className: 'FlowGridEl-base',
}).withConfig({
  shouldForwardProp: (key) => !['gapX','gapY','cols'].includes(key),
})`${({ gapY, cols }) => [
  cols && outputFunctions.cols(cols),
  gapY && outputFunctions.gapY(gapY),
]}`;

/* eslint-enable prettier/prettier */

export const Flow = forwardRef(
  ({ as, gap, gapY = gap, gapX = gap, span, cols = span, ai, jc, children, ...restProps }, ref) => {
    return (
      <Stop {...{ span, ...restProps }}>
        <FlowEl ref={ref} forwardedAs={as} {...{ gapX, gapY, cols, ai, jc }}>
          {children}
        </FlowEl>
      </Stop>
    );
  },
);
Flow.displayName = 'Flow';

export const FlowGrid = forwardRef(
  ({ as, gap, gapY = gap, gapX = gap, span, cols = span, children, ...restProps }, ref) => {
    return (
      <Stop {...{ span, ...restProps }}>
        <FlowGridEl ref={ref} forwardedAs={as} {...{ gapX, gapY, cols }}>
          {children}
        </FlowGridEl>
      </Stop>
    );
  },
);
FlowGrid.displayName = 'FlowGrid';
