import Foundation

public class CodeGenerator {
  let astOutput: ASTOutput

  private var singleFileOutputs = [String]()
  
  public init(astOutputURL url: URL) throws {
    let data = try Data(contentsOf: url)
    self.astOutput = try JSONDecoder().decode(ASTOutput.self, from: data)    
  }
  
  public func run(with options: ApolloCodegenOptions) throws {
    try self.generateTypesUsed(with: options)
    try self.generateFragments(with: options)
    try self.generateOperations(with: options)
    
    switch options.outputFormat {
    case .singleFile(let fileURL):
      let joinedContent = self.singleFileOutputs.joined(separator: "\n\n")
      try self.writeOutput(joinedContent, toFile: fileURL)
    case .multipleFiles:
      // This is done as each file is generated.
      break
    }
  }
  
  private func generateTypesUsed(with options: ApolloCodegenOptions) throws {
    for type in self.astOutput.typesUsed {
      switch type.kind {
      case .EnumType:
        let enumOutput = try EnumGenerator().run(typeUsed: type, options: options)
        try self.renderOutput(enumOutput, named: type.name, with: options)
      case .InputObjectType:
        try self.renderOutput("Not done yet", named: type.name, with: options)
      }
    }
  }
  
  private func generateFragments(with options: ApolloCodegenOptions) throws {
    // TODO!
  }
  
  private func generateOperations(with options: ApolloCodegenOptions) throws {
    // TODO
  }
  
  private func renderOutput(_ output: String,
                    named name: String,
                    with options: ApolloCodegenOptions) throws {
    switch options.outputFormat {
    case .singleFile:
      self.singleFileOutputs.append(output)
    case .multipleFiles(let folderURL):
      try self.createFileWithOutput(output,
                                    named: name,
                                    inFolder: folderURL)
    }
  }
  
  private func createFileWithOutput(_ output: String,
                                    named name: String,
                                    inFolder folderURL: URL) throws {
    try FileManager.default.apollo.createFolderIfNeeded(at: folderURL)
    let fileURL = folderURL
      .appendingPathComponent(name)
      .appendingPathExtension("swift")
    
    try self.writeOutput(output, toFile: fileURL)
  }
    
  private func writeOutput(_ output: String,
                           toFile fileURL: URL) throws {
    let finalOutput = """
    // @generated
    // This file was automatically generated by apollo-ios and should not be edited.

    """ + output

    try finalOutput.write(to: fileURL,
                          atomically: true,
                          encoding: .utf8)
  }
}
