import { DefInfo, getReferencedTypes, getRef } from './util';
import * as _ from 'underscore';
import * as path from 'path';
import * as fs from 'fs';
import * as mkdirp from 'mkdirp';
import { OpenAPIObject, SchemaObject, ReferenceObject } from 'openapi3-ts';

export function generateHeader(doc: OpenAPIObject): string {
  const { info } = doc;
  return `/**
 * ${info.title}
 * ${info.description}
 *
 * OpenAPI spec version: ${info.version}
 * Contact: ${info.contact!.email}
 *
 * NOTE: This class is auto generated by the bungie-api-ts code generator program.
 * https://github.com/DestinyItemManager/bugie-api-ts
 * Do not edit these files manually.
 */`;
}

export function addImport(
  doc: OpenAPIObject,
  schema: SchemaObject | ReferenceObject,
  componentByDef: {[def: string]: DefInfo },
  importFiles: { [filename: string]: Set<string> }
) {
  const typeRef = getReferencedTypes(schema);
  if (typeRef && componentByDef[typeRef]) {
    if (typeRef.includes('/responses/')) {
      const component = getRef(doc, typeRef);
      if (component) {
        const property = component.properties!.Response;
        if (property) {
          importFiles['common.ts'] = importFiles['common.ts'] || new Set();
          importFiles['common.ts'].add('ServerResponse');
          addImport(doc, property, componentByDef, importFiles);
          return;
        }
      }
    }

    const filename = componentByDef[typeRef].filename;
    importFiles[filename] = importFiles[filename] || new Set();
    importFiles[filename].add(componentByDef[typeRef].interfaceName);
  }
}

export function generateImports(filename: string , importFiles: { [filename: string]: Set<string> }): string {
  return _.compact(_.map(importFiles, (types, f) => {
    const absImport = path.resolve('generated-src', f);
    const absDest = path.resolve(filename);
    if (absImport === absDest) {
      return undefined;
    }
    let relativePath = path.relative(path.dirname(absDest), absImport).replace(/(\.d)?\.ts$/, '');
    if (!relativePath.startsWith('.')) {
      relativePath = './' + relativePath;
    }
    return `import {
  ${[...types].sort().join(',\n  ')}
} from '${relativePath}';`;
  })).sort().join("\n");
}

export function docComment(text: string) {
  const lines = _.flatten(text.trim().split('\n').map((l) => l.replace(/(.{1,80}(?:\W|$))/g, '$1\n').split('\n'))).map((s: string) => s.trim());
  lines.pop();

  if (lines.length === 1) {
    return `/** ${lines} */`;
  }

  return `/**
${lines.map((line) => line.length ? ' * ' + line : ' *').join('\n')}
 */`;
}

export function indent(text: string, indentLevel: number) {
  const lines = text.split('\n');
  return lines.map((line) => '  '.repeat(indentLevel) + line).join('\n');
}

export function writeOutFile(filename: string, contents: string) {
  mkdirp(path.dirname(filename), (err) => {
    if (err) {
      console.error(err);
    } else {
      fs.writeFile(filename, contents, null, (error) => {
        console.log(error ? error : `Done with ${filename}!`);
      });
    }
  });
}
