import { React, css, log, describe } from '../../../test/storybook';
import { CodeEditor, ICodeEditorProps, CodeEditorChangeEvent } from '..';

const STORY = {
  title: 'Code editor.',
  width: '100%',
  height: '100%',
  padding: 30,
  hr: false,
  flex: true,
};

const CODE = `
/**
 * Comments.
 */
const FOO = 123;
const func = (arg) => true;

`.substr(1);

const PKG = require('../../../../package.json');
const CODE_JSON = JSON.stringify(PKG, null, '  ');

describe('CodeEditor/options', STORY)
  .add('fontSize: (default)', () => <Test />)
  .add('fontSize: large', () => <Test options={{ fontSize: 32 }} />)
  .add('fontSize: small', () => <Test options={{ fontSize: 10 }} />)
  .add('tabSize: 2 (default)', () => <Test options={{ tabSize: 2 }} />)
  .add('tabSize: 4', () => <Test options={{ tabSize: 4 }} />)
  .add('readOnly', () => <Test options={{ readOnly: true }} />);

describe('CodeEditor/options (theme)', STORY)
  .add('DARK (default)', () => <Test />)
  .add('LIGHT', () => <Test options={{ theme: 'LIGHT' }} />);

describe('CodeEditor/options (language)', STORY)
  .add('json', () => {
    return <Test options={{ language: 'json' }} code={CODE_JSON} />;
  })
  .add('typescript (default)', () => {
    return <Test options={{ language: 'typescript' }} />;
  })
  .add('javascript', () => {
    return <Test options={{ language: 'javascript' }} />;
  })
  .add('types (string)', () => {
    const types = [
      `
      /**
       * My kind of Type.
       */
      declare type MyThing = {
        count: number;
        text?: string;
      }
    `,
      `
      /**
       * A Foo that foo's the next foo.
       */
      class Foo {
        static next(): string;
      }
    `,
    ];
    const code = `
Foo.next();
const foo:MyThing = { count:123 };
`.substr(1);
    return <Test options={{ typescriptDefaults: { types } }} code={code} />;
  })
  .add('types (".d.ts" file)', () => {
    const def = require('./test.types-1.d.ts') as string;
    const code = `
async function go() {
  await MyClass.doSomething();
  const foo: MySuperFoo = {
    counter: 123,
    async magic() { return 'hello'; }
  }
}
`.substr(1);
    return (
      <Test options={{ typescriptDefaults: { types: [def] } }} code={code} />
    );
  })
  .add('different sets of types', () => {
    const def1 = require('./test.types-1.d.ts') as string;
    const def2 = require('./test.types-2.d.ts') as string;
    const code1 = 'MyClass.doSomething();';

    const styles = {
      base: css({
        Flex: 'vertical-stretch-stretch',
        flex: 1,
      }),
      outer: css({
        position: 'relative',
        flex: 1,
        marginTop: 5,
        ':first-child': { marginTop: 0 },
      }),
    };

    return (
      <div {...styles.base}>
        <div {...styles.outer}>
          <Test
            options={{ typescriptDefaults: { types: [def1] } }}
            code={code1}
          />
        </div>
        <div {...styles.outer}>
          <Test
            options={{ typescriptDefaults: { types: [def2] } }}
            code={code1}
          />
        </div>
      </div>
    );
  });

const DIFF_AFTER = `
const FOO = 123;

`;
const DIFF_BEFORE = `
const FOO = 456;
console.log(FOO);

`;
describe('CodeEditor/diff', STORY)
  .add('side-by-side (default)', () => {
    return <Test code={DIFF_AFTER} diff={{ code: DIFF_BEFORE }} />;
  })
  .add('inline', () => {
    return (
      <Test code={DIFF_AFTER} diff={{ code: DIFF_BEFORE, inline: true }} />
    );
  });

/**
 * INTERNAL
 */
interface ITestState {
  code?: string;
}
class Test extends React.PureComponent<ICodeEditorProps, ITestState> {
  public state: ITestState = { code: this.props.code || CODE };

  public render() {
    return (
      <CodeEditor
        {...this.props}
        code={this.state.code}
        onChange={this.handleChange}
        style={{ Absolute: 0 }}
      />
    );
  }

  private handleChange = (e: CodeEditorChangeEvent) => {
    log.info('!! onChange', e);
    this.setState({ code: e.code });
  };
}
