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

import type { JSX, PropsWithChildren } from 'react';

import { generateCodeBlockTokens } from '@redocly/theme/core/utils';

export type CodeBlockContainerProps = PropsWithChildren<{
  hideCodeColors?: boolean;
  maxHeight?: string;
  wrapContents?: boolean;
  ref?: (instance: HTMLPreElement | null) => void;
  className?: string;
  withLineNumbers?: boolean;
  dangerouslySetInnerHTML?: {
    __html: string;
  };
  suppressHydrationWarning?: boolean;
  tabIndex?: number;
}>;

export function CodeBlockContainer(props: CodeBlockContainerProps): JSX.Element {
  return (
    <CodeBlockContainerComponent {...props} data-component-name="CodeBlock/CodeBlockContainer" />
  );
}

const CodeBlockContainerComponent = styled.pre<CodeBlockContainerProps>`
  && {
    overflow-x: auto;
    font-family: var(--code-block-font-family);
    line-height: var(--code-block-line-height);
    font-weight: var(--code-block-font-weight);
    padding: var(--code-block-padding);
    margin: var(--code-block-margin);
    color: var(--code-block-text-color);
    font-size: var(--code-block-font-size);
    white-space: ${({ wrapContents }) => (wrapContents ? 'pre-wrap' : 'var(--code-wrap, pre)')};
    max-height: ${({ maxHeight }) =>
      maxHeight ? maxHeight : 'var(--code-block-max-height, 600px);'};
    word-break: var(--code-block-word-break, initial);

    pre,
    code {
      font-family: var(--code-block-font-family);
    }
  }

  .highlighted {
    background: var(--code-block-highlighted-bg-color);
    margin-left: calc(var(--spacing-sm) * -1);
    padding-left: var(--spacing-sm);
    width: calc(100% + var(--spacing-sm));
    display: inline-block;
    border-left: var(--code-block-highlighted-border-left);

    &.error {
      background: var(--color-error-bg);
      border-left: 1px solid var(--color-error-base);
    }

    &.warning {
      background: var(--color-warning-bg);
      border-left: 1px solid var(--color-warning-base);
    }
  }

  [data-line-number] {
    &::before {
      content: attr(data-line-number);
      display: inline-block;
      min-width: 2em;
      padding-right: 0.8em;
      text-align: right;
      pointer-events: none;
      user-select: none;
    }
  }

  .has-diff {
    > .line {
      &::before {
        content: attr(data-line-number) '  ';
        display: inline-block;
        padding-right: 0.4em;
        text-align: right;
        pointer-events: none;
        user-select: none;
      }
      &[data-line-number]::before {
        min-width: 3em;
      }
    }
  }

  .diff {
    margin-left: calc(var(--spacing-sm) * -1);
    padding-left: var(--spacing-sm);
    width: calc(100% + var(--spacing-sm));
    display: inline-block;

    &.add {
      background: var(--color-success-bg);
      border-left: 1px solid var(--color-success-base);
      &:before {
        content: attr(data-line-number) ' +';
        color: var(--color-success-active);
      }
    }
    &.remove {
      background: var(--color-error-bg);
      border-left: 1px solid var(--color-error-base);

      &:before {
        content: attr(data-line-number) ' -';
        color: var(--color-error-active);
      }
    }
  }

  .highlighted-word {
    background: var(--color-carrot-2);
    border: 1px solid var(--color-carrot-5);
    border-radius: 4px;
  }

  .has-focused {
    .line {
      margin-left: calc(var(--spacing-sm) * -1);
      padding-left: var(--spacing-sm);
      width: calc(100% + var(--spacing-sm));
      display: inline-block;

      opacity: 0.7;
      filter: blur(0.095rem);
      transition:
        filter 0.35s,
        opacity 0.35s;
      &.focused {
        opacity: 1;
        filter: blur(0);
      }
    }

    &:hover {
      .line {
        opacity: 1;
        filter: blur(0);
      }
    }
  }

  /*
  * Tree view styles
   */

  .shiki {
    &.theme {
      display: inline-block;
      width: 100%;

      &.tree-view-root {
        display: flex;
        flex-direction: column;
      }
    }
  }

  . .line {
    display: inline-block;
  }

  .tree-view-line {
    display: flex;
  }

  .tree-view-comment {
    color: var(--code-block-tree-view-comment-color);
  }

  .tree-view-branch {
    color: var(--code-block-tree-view-lines-color);
  }

  .tree-view-file {
    display: inline-flex;
    &::before {
      content: '\\ea01';
      margin-left: 0.3rem;
      margin-right: 0.5rem;
      font-family: 'TreeViewIcons';
    }

    &.no-file {
      &::before {
        content: '';
        margin-right: 0;
      }
    }

    &.ext-folder {
      &::before {
        content: '\\ea02';
      }
    }

    &.ext-img,
    &.ext-png,
    &.ext-jpg,
    &.ext-jpeg,
    &.ext-gif,
    &.ext-svg {
      &::before {
        content: '\\ea03';
      }
    }

    &.ext-mp2,
    &.ext-mp3,
    &.ext-wav,
    &.ext-ogg,
    &.ext-flac {
      &::before {
        content: '\\ea04';
      }
    }

    &.ext-mp4,
    &.ext-mkv,
    &.ext-avi,
    &.ext-mov,
    &.ext-wmv,
    &.ext-flv {
      &::before {
        content: '\\ea05';
      }
    }

    &.ext-txt,
    &.ext-text,
    &.ext-md,
    &.ext-markdown {
      &::before {
        content: '\\ea06';
      }
    }

    &.ext-js,
    &.ext-ts,
    &.ext-jsx,
    &.ext-tsx,
    &.ext-json,
    &.ext-yaml,
    &.ext-yml,
    &.ext-xml,
    &.ext-html,
    &.ext-css,
    &.ext-scss,
    &.ext-less,
    &.ext-sass,
    &.ext-java,
    &.ext-c,
    &.ext-cpp,
    &.ext-cs,
    &.ext-php,
    &.ext-py,
    &.ext-rb,
    &.ext-go,
    &.ext-swift,
    &.ext-sql,
    &.ext-perl,
    &.ext-lua,
    &.ext-scala,
    &.ext-sh {
      &::before {
        content: '\\ea07';
      }
    }

    &.ext-zip,
    &.ext-rar,
    &.ext-tar,
    &.ext-gz,
    &.ext-iso {
      &::before {
        content: '\\ea08';
      }
    }

    &.ext-pdf,
    &.ext-PDF {
      &::before {
        content: '\\ea09';
      }
    }

    &.ext-excel,
    &.ext-xls,
    &.ext-xlsx {
      &::before {
        content: '\\ea0a';
      }
    }

    &.ext-powerpoint,
    &.ext-ppt,
    &.ext-pptx {
      &::before {
        content: '\\ea0b';
      }
    }

    &.ext-doc,
    &.ext-docx,
    &.ext-rtf {
      &::before {
        content: '\\ea0c';
      }
    }
  }

  ${generateCodeBlockTokens()}

  ${({ hideCodeColors }) =>
    hideCodeColors &&
    css`
      .line-number:not(.highlighted),
      .line-number:not(.highlighted) > span,
      .line-number:not(.highlighted) > span > span {
        color: grey;
      }
    `}
`;
