import {
  TagProps,
  global,
// } from '@declaration'
} from '../@declaration/_'

import {
  getInstance,
  $
} from './_'

type StyleType = 'amotf_' | 'amotf_bp'

const FNs = {
  toConcreteBorderRadius: ( br?: TagProps.Borders.Radius ) => {
    let roundness = getInstance().config.roundness | 0

    if ( br == '1.tone.primary' ) {
      br = [ 0,2,3,4,5,5 ][ roundness ] as TagProps.Borders.Radius
    } else if ( br == '2.tone.secondary' ) {
      br = [ 0,1,2,3,4,5 ][ roundness ] as TagProps.Borders.Radius
    } else if ( br == '3.tone.tertiary' ) {
      br = [ 0,'1/3','2/3',1,2,3 ][ roundness ] as TagProps.Borders.Radius
    }
    return br
  },
  ev: ( v: any ) => $.is.nullish( v ),
  ClassNames: ( type: StyleType,params: TagProps.Params ) => {
    let CLS: string[] = []

    let {
      gap,

      display: disp,
      position,
      overflow,
      fontColor,fontSize,fontWeight,
      backgroundColor: bgc,
      textAlign,
      boxShadow,

      margin: mrg,
      marginTop: mrgT,
      marginRight: mrgR,
      marginBottom: mrgB,
      marginLeft: mrgL,

      padding: pd,
      paddingTop: pdT,
      paddingRight: pdR,
      paddingBottom: pdB,
      paddingLeft: pdL,

      top: T,
      right: R,
      bottom: B,
      left: L,

      border: b,
      borderTop: bT,
      borderRight: bR,
      borderBottom: bB,
      borderLeft: bL,

      borderWidth: bWidth,
      // borderTopWidth: bTWidth,
      // borderRightWidth: bRWidth,
      // borderBottomWidth: bBWidth,
      // borderLeftWidth: bLWidth,

      borderColor: bColor,
      // borderTopColor: bTColor,
      // borderRightColor: bRColor,
      // borderBottomColor: bBColor,
      // borderLeftColor: bLColor,

      borderStyle: bStyle,
      // borderTopStyle: bTStyle,
      // borderRightStyle: bRStyle,
      // borderBottomStyle: bBStyle,
      // borderLeftStyle: bLStyle,

      borderRadius: br,
      borderTopLeftRadius: brTL,
      borderTopRightRadius: brTR,
      borderBottomLeftRadius: brBL,
      borderBottomRightRadius: brBR,



      flexSizing,
      flexWrap,
      flexType,
      flexChilds,
      flexGrid,
      horizontalAlign,
      verticalAlign,

      transition,

      gridCenter,
      gridCols,
      maxHeight,minHeight,maxWidth,minWidth,
      width,height,
      unitHeight,unitWidth,

      opacity,

      ...others
    } = params

    {
      FNs.ev( disp ) || CLS.push( 'dsp' + disp )

      if ( overflow ) {
        let arr = $.flatArray( overflow )
        CLS.push( 'ovfl-x-' + arr[ 0 ] )
        CLS.push( 'ovfl-y-' + ( arr[ 1 ] || arr[ 0 ] ) )
      }

      FNs.ev( position ) || ( CLS.push( 'ps' + position ) )
      FNs.ev( textAlign ) || ( CLS.push( 'txalg' + textAlign ) )

      FNs.ev( fontColor ) || ( CLS.push( 'ftcl' + String( fontColor )?.replace( /\..*/,'' ) ) )

      FNs.ev( fontSize ) || ( CLS.push( 'ftsz' + String( fontSize )?.replace( /\..*/,'' ) ) )
      FNs.ev( fontWeight ) || ( CLS.push( 'ftwt' + fontWeight?.replace( /\..*/,'' ) ) )

      FNs.ev( bgc ) || CLS.push( 'bgc' + String( bgc )?.replace( /\..*/,'' ) )

      FNs.ev( boxShadow ) || ( CLS.push( 'bs' + boxShadow ) )

      let _mrgT,_mrgR,_mrgB,_mrgL
      if ( $.is.exist( mrg ) ) {
        if ( $.is.array( mrg ) ) {
          if ( mrg.length == 2 ) [ _mrgT,_mrgR,_mrgB,_mrgL ] = [ ...mrg,...mrg ]
          else if ( mrg.length == 4 ) [ _mrgT,_mrgR,_mrgB,_mrgL ] = mrg
        } else _mrgT = _mrgR = _mrgB = _mrgL = mrg
        mrgT = mrgT ?? _mrgT
        mrgR = mrgR ?? _mrgR
        mrgB = mrgB ?? _mrgB
        mrgL = mrgL ?? _mrgL
      }
      FNs.ev( mrgT ) || ( CLS.push( 'mrgt' + mrgT ) )
      FNs.ev( mrgR ) || ( CLS.push( 'mrgr' + mrgR ) )
      FNs.ev( mrgB ) || ( CLS.push( 'mrgb' + mrgB ) )
      FNs.ev( mrgL ) || ( CLS.push( 'mrgl' + mrgL ) )

      let _pdT,_pdR,_pdB,_pdL
      if ( $.is.exist( pd ) ) {
        if ( $.is.array( pd ) ) {
          if ( pd.length == 2 ) [ _pdT,_pdR,_pdB,_pdL ] = [ ...pd,...pd ]
          else if ( pd.length == 4 ) [ _pdT,_pdR,_pdB,_pdL ] = pd
        } else _pdT = _pdR = _pdB = _pdL = pd
        pdT = pdT ?? _pdT
        pdR = pdR ?? _pdR
        pdB = pdB ?? _pdB
        pdL = pdL ?? _pdL
      }
      FNs.ev( pdT ) || ( CLS.push( 'pdt' + pdT ) )
      FNs.ev( pdR ) || ( CLS.push( 'pdr' + pdR ) )
      FNs.ev( pdB ) || ( CLS.push( 'pdb' + pdB ) )
      FNs.ev( pdL ) || ( CLS.push( 'pdl' + pdL ) )

      FNs.ev( T ) || ( CLS.push( 'pstt' + T ) )
      FNs.ev( R ) || ( CLS.push( 'pstr' + R ) )
      FNs.ev( B ) || ( CLS.push( 'pstb' + B ) )
      FNs.ev( L ) || ( CLS.push( 'pstl' + L ) )

      {
        {
          if ( $.is.exist( b ) ) {
            bT = bT ?? b
            bR = bR ?? b
            bB = bB ?? b
            bL = bL ?? b
          }
          if ( $.is.boolean( bT ) ) bT = [ 'unset','2.normal' ][ Number( bT ) ] as TagProps.Borders.Border
          if ( $.is.boolean( bR ) ) bR = [ 'unset','2.normal' ][ Number( bR ) ] as TagProps.Borders.Border
          if ( $.is.boolean( bB ) ) bB = [ 'unset','2.normal' ][ Number( bB ) ] as TagProps.Borders.Border
          if ( $.is.boolean( bL ) ) bL = [ 'unset','2.normal' ][ Number( bL ) ] as TagProps.Borders.Border
          FNs.ev( bT ) || ( CLS.push( 'b_t_ss' + String( bT )?.replace( /\..*/,'' ) ) )
          FNs.ev( bR ) || ( CLS.push( 'b_r_ss' + String( bR )?.replace( /\..*/,'' ) ) )
          FNs.ev( bB ) || ( CLS.push( 'b_b_ss' + String( bB )?.replace( /\..*/,'' ) ) )
          FNs.ev( bL ) || ( CLS.push( 'b_l_ss' + String( bL )?.replace( /\..*/,'' ) ) )
        }
        if ( $.is.exist( bWidth ) ) CLS.push( 'b_wth' + String( bWidth ) )
        if ( $.is.exist( bColor ) ) CLS.push( 'b_cl' + String( bColor ) )
        if ( $.is.exist( bStyle ) ) CLS.push( 'b_st' + String( bStyle ) )

        {
          let _brTL,_brTR,_brBL,_brBR
          if ( $.is.exist( br ) ) {
            if ( $.is.array( br ) ) {
              if ( br.length == 4 ) [ _brTL,_brTR,_brBR,_brBL ] = br
            } else {
              _brTL = _brTR = _brBL = _brBR = br
            }
            brTL = brTL ?? _brTL
            brTR = brTR ?? _brTR
            brBL = brBL ?? _brBL
            brBR = brBR ?? _brBR
          }
        }
        FNs.ev( brTL ) || ( CLS.push( 'br_tl' + FNs.toConcreteBorderRadius( brTL ) ) )
        FNs.ev( brTR ) || ( CLS.push( 'br_tr' + FNs.toConcreteBorderRadius( brTR ) ) )
        FNs.ev( brBL ) || ( CLS.push( 'br_bl' + FNs.toConcreteBorderRadius( brBL ) ) )
        FNs.ev( brBR ) || ( CLS.push( 'br_br' + FNs.toConcreteBorderRadius( brBR ) ) )
      }

      FNs.ev( opacity ) || ( CLS.push( 'op' + opacity ) )

      if ( $.is.exist( gap ) ) {
        let gapRow,gapCol
        if ( $.is.array( gap ) ) gapRow = gap[ 0 ],gapCol = gap[ 1 ]
        else gapRow = gapCol = gap
        CLS.push( ...[ 'gapRow' + gapRow,'gapCol' + gapCol ] )
      }

      FNs.ev( flexSizing ) || ( CLS.push( 'flsz' + flexSizing ) )
      FNs.ev( flexWrap ) || ( CLS.push( 'flwrp' + flexWrap ) )
      FNs.ev( flexType ) || ( CLS.push( 'fltyp' + flexType ) )
      FNs.ev( flexChilds ) || ( CLS.push( 'flchld' + flexChilds ) )
      FNs.ev( flexGrid ) || ( CLS.push( 'flgrid' + flexGrid ) )
      FNs.ev( verticalAlign ) || ( CLS.push( 'flvrt' + verticalAlign ) )
      FNs.ev( horizontalAlign ) || ( CLS.push( 'flhrz' + horizontalAlign ) )

      FNs.ev( gridCenter ) || ( CLS.push( 'grcnt' + gridCenter ) )
      FNs.ev( gridCols ) || ( CLS.push( 'grcol' + gridCols ) )

      FNs.ev( height ) || ( CLS.push( 'hgt' + height ) )
      FNs.ev( width ) || ( CLS.push( 'wdt' + width ) )

      FNs.ev( unitHeight ) || ( CLS.push( 'unthgt' + unitHeight ) )
      FNs.ev( unitWidth ) || ( CLS.push( 'untwdt' + unitWidth ) )

      FNs.ev( transition ) || ( CLS.push( 'trnst' + transition ) )

      FNs.ev( maxHeight ) || ( CLS.push( 'maxh' + maxHeight ) )
      FNs.ev( minHeight ) || ( CLS.push( 'minh' + minHeight ) )
      FNs.ev( maxWidth ) || ( CLS.push( 'maxw' + maxWidth ) )
      FNs.ev( minWidth ) || ( CLS.push( 'minw' + minWidth ) )
    }

    return {
      otherParams: others,
      className: CLS.length ? type + CLS.join( ' ' + type ) : ''
    }
  }
}

export const ReadStyleSet: global.StyleConverter.ReadStyleSet = ( rawParams ) => {
  let params: TagProps.BasicElement = { ...rawParams } as any
  let {
    gradients,
    ssCardBox,
    ssSphere,
    ssSquare,
    ssPushable,
    ssAbsoluteCovered,
    ssTextEllipsis,
    flexCenter,
    flexNewLine,

    isLightFont,
    isBoldFont,
    isSemiBoldFont,
    isRounded,
    ...ReturnParams
  } = params

  if ( gradients ) {
    let {
      deg,
      colors
    } = gradients

    ReturnParams = {
      ...ReturnParams,
      freeCSS: {
        ...ReturnParams.freeCSS,
        background: `linear-gradient(${ deg }deg,${ colors.join( ',' ) })`,
      }
    }
  }
  if ( ssCardBox ) {
    if ( ssCardBox === true ) {
      ssCardBox = 'border'
    }

    let exStyles: TagProps.Params = {
      backgroundColor: '1.layer.base',
      borderRadius: '1.tone.primary',
      boxShadow: '0.thin',
      freeCSS: {
        zIndex: 1
      }
    }

    if ( ssCardBox == 'border' ) {
      exStyles.border = true
    } else if ( ssCardBox == 'layer' ) {
      exStyles.backgroundColor = '1.layer.base'
    } else if ( ssCardBox == 'cloud' ) {
      exStyles.backgroundColor = 'cloud'
    } else if ( ssCardBox == 'shadow' ) {
      exStyles.boxShadow = '0.normal'
    }

    if ( [ 'dim','dark' ].includes( getInstance().config.darkMode ) ) exStyles.boxShadow = '1.remark'
    ReturnParams = {
      ...exStyles,
      ...ReturnParams,
      freeCSS: {
        ...exStyles.freeCSS,
        ...ReturnParams.freeCSS
      },
      UnderBreakPointStyles: {
        ...exStyles.UnderBreakPointStyles,
        ...ReturnParams.UnderBreakPointStyles
      }
    }
  }
  if ( ssSphere ) {
    flexCenter = flexCenter ?? true
    ReturnParams = {
      padding: 0,
      unitWidth: ssSphere,
      unitHeight: ssSphere,
      borderRadius: 'sphere',
      flexSizing: 'none',
      ...ReturnParams,
    }
  }
  if ( ssSquare ) {
    flexCenter = flexCenter ?? true
    ReturnParams = {
      padding: 0,
      unitWidth: ssSquare,
      unitHeight: ssSquare,
      flexSizing: 'none',
      ...ReturnParams,
    }
  }

  !ssPushable || ( ReturnParams = {
    transition: 'middle',
    ...ReturnParams,
    className: [
      ReturnParams.className,
      'ssPushable'
    ].join( ' ' )
  } )

  !ssAbsoluteCovered || ( ReturnParams = {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    ...ReturnParams
  } )
  !ssTextEllipsis || ( ReturnParams = {
    overflow: 'hidden',
    ...ReturnParams,
    freeCSS: {
      whiteSpace: 'nowrap',
      textOverflow: 'ellipsis',
      ...ReturnParams.freeCSS
    }
  } )
  !flexNewLine || ( ReturnParams = {
    width: 1,
    flexSizing: 'none',
    ...ReturnParams
  } )
  !flexCenter || ( ReturnParams = {
    display: 'flex',
    horizontalAlign: 'center',
    verticalAlign: 'center',
    ...ReturnParams
  } )
  !isLightFont || ( ReturnParams = {
    ...ReturnParams,
    fontWeight: '1.light',
  } )
  !isSemiBoldFont || ( ReturnParams = {
    ...ReturnParams,
    fontWeight: '3.semiBold',
  } )
  !isBoldFont || ( ReturnParams = {
    ...ReturnParams,
    fontWeight: '4.bold',
  } )
  !isRounded || ( ReturnParams = {
    ...ReturnParams,
    borderRadius: 'sphere'
  } )

  return ReturnParams as any
}
export const GenerateClassName: global.StyleConverter.ToClassName = ( rawParams ) => {
  let params = ReadStyleSet( rawParams ) as TagProps.BasicElement

  let {
    componentID,
    UnderBreakPointStyles = {},

    className = '',

    freeCSS = {},

    ssEffectsOnActive,
    ssLastChildLossBorder,
    ...others
  } = params

  let ClassNames = [ className ]

  if ( ssLastChildLossBorder ) {
    ClassNames.push( 'ssLastChildLossBorder_' + ssLastChildLossBorder )
  }

  if ( ssEffectsOnActive ) {
    ssEffectsOnActive = $.flatArray( ssEffectsOnActive )
    for ( let effect of ssEffectsOnActive as any[] ) ClassNames.push( ...[ 'eff_' + effect,'eff_' + effect.split( '.' )[ 0 ] ] )
  }

  {
    let result = FNs.ClassNames( 'amotf_',others )

    ClassNames.push( result.className )
    others = result.otherParams
  }
  if ( UnderBreakPointStyles ) ClassNames.push( FNs.ClassNames( 'amotf_bp',UnderBreakPointStyles ).className )

  let states = { ...others } as any
  if ( freeCSS ) states.style = {
    ...freeCSS,
    ...states.style
  }

  if ( componentID || states[ 'data-component-id' ] ) {
    states[ 'data-component-id' ] = states[ 'data-component-id' ] || componentID
  }

  if ( ClassNames.length ) {
    states.className = ClassNames.join( ' ' )
      .trim()
      .replace( /%/ig,'P' )
      .replace( /\d+px/ig,'PIX' )
      .replace( /\s+/ig,' ' )
      .replace( /\//ig,'_' )
      .replace( /\./ig,'-' )
  }
  return states
}