import { CodeRW, CodeDir } from '@iteria-app/generator/src/io'
import { IntrospectionQuery } from '@iteria-app/graphql-lowcode'
import { WindowMessaging } from '../messaging'

export interface FileWriteData {
  path: string
  data: string
}

export interface DirectoryFiles {
  fileName?: string
  filePath?: string
}

export class DevWorkbench implements CodeRW, CodeDir {
  constructor(messagingService: WindowMessaging, fsPort?: number) {
    this.messagingService = messagingService
    this.fsPort = fsPort ?? 7500

    this.messagingService.addEventListener<FileWriteData>(
      'FILE_WRITE',
      ({ data, path }) => this.writeFile(path, data)
    )

    this.messagingService.addEventListener<FileWriteData[]>(
      'MULTIPLE_FILE_WRITE',
      (data) => this.writeFiles(data)
    )
  }

  private messagingService: WindowMessaging
  private fsPort: number
  public graphQLEndpoint: string
  public introspection: IntrospectionQuery

  async readFile(path: string, encoding?: string) {
    try {
      const res = await fetch('/__fetchfs/read/file/', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ path: path }),
      })
      const data = await res.text()
      return data
    } catch (err) {
      console.error(
        `Error while reading file from local FS, make sure fs-over-http is running on port: ${this.fsPort}`,
        err
      )
    }
  }

  async readDirectory(
    path: string,
    extensions?: readonly string[],
    exclude?: readonly string[],
    include?: readonly string[],
    depth?: number
  ): Promise<string[]> {
    try {
      const res = await fetch('/__fetchfs/read/dir/', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ path: path }),
      })
      const filesPath = await res.text()
      return this.createDirectoryObject(filesPath) as any
    } catch (err) {
      console.error(
        `Error while reading file from local FS, make sure fs-over-http is running on port: ${this.fsPort}`,
        err
      )
    }
  }

  async writeFile(path: string, data: string) {
    try {
      await fetch('/__fetchfs/write/file/', {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ path: path, data: data }),
      })
    } catch (err) {
      console.error(
        `Error while writing file to local FS, make sure fs-over-http is running on port: ${this.fsPort}`,
        err
      )
    }
  }

  async writeFiles(files: FileWriteData[]) {
    files.forEach((f) => this.writeFile(f.path, f.data))
  }

  setPort(fsPort: number) {
    this.fsPort = fsPort
  }

  setGraphQLEndpoint(graphQLEndpoint: string) {
    this.graphQLEndpoint = graphQLEndpoint
  }

  setIntrospection(introspection: IntrospectionQuery) {
    this.introspection = introspection
  }

  createDirectoryObject(response: string): DirectoryFiles[] {
    let filesOfDirectory: DirectoryFiles[] = []
    response = response
      .replace(/\[/g, '')
      .replace(/\]/g, '')
      .replace(/\\/g, '/')
      .replace(/\"/g, '')
    const arr = response.split(',')
    for (let item in arr) {
      const parsedPath = arr[item].split('/')
      const objToPush: DirectoryFiles[] = [
        { fileName: parsedPath.pop(), filePath: arr[item] },
      ]
      filesOfDirectory = [...filesOfDirectory, ...objToPush]
    }
    return filesOfDirectory
  }
}
