import { IRequestLog } from './RequestLog.js'

export const Kind = 'Core#ProjectExecution'

export interface IProjectExecutionIteration {
  /**
   * The index of the iteration.
   */
  index: number
  /**
   * The list of requests executed in the iteration.
   */
  executed: IRequestLog[]
  /**
   * The variables evaluated during the run.
   * These variables have values set by requests' HTTP flows.
   */
  variables: Record<string, string>
  /**
   * Optional general error message.
   */
  error?: string
}

export interface IProjectExecutionLog {
  /**
   * The timestamp when the execution started
   */
  started: number
  /**
   * The timestamp when the execution ended
   */
  ended: number
  /**
   * The execution logs for each iteration.
   */
  iterations: IProjectExecutionIteration[]
}

export interface IProjectExecution extends IProjectExecutionLog {
  kind: typeof Kind
  /**
   * The key of the execution entry. This is generated by the store. Client value is ignored.
   */
  key: string

  /**
   * The key of the parent project.
   */
  project: string

  /**
   * The key of the parent folder, if any.
   */
  parent?: string

  /**
   * The application id that generated the entry.
   */
  app: string

  /**
   * The user id that made that request.
   * This is only available when the store support multi-user environment.
   */
  user?: string

  /**
   * A timestamp of the midnight when the object was created.
   */
  midnight: number
}

export class ProjectExecution implements IProjectExecution {
  kind: typeof Kind = Kind

  /**
   * The key of the execution entry. This is generated by the store. Client value is ignored.
   */
  key = ''

  /**
   * The key of the parent project.
   */
  project = ''

  /**
   * The key of the parent folder, if any.
   */
  parent?: string

  /**
   * The application id that generated the entry.
   */
  app = ''

  /**
   * The user id that made that request.
   * This is only available when the store support multi-user environment.
   */
  user?: string

  /**
   * @param value The timestamp of the midnight when the request object was updated
   */
  set midnight(value: number | undefined) {
    if (!value) {
      this.midnightInternal = this.defaultMidnight()
    } else {
      this.midnightInternal = value
    }
  }

  /**
   * @returns The timestamp of the midnight when the request object was updated
   */
  get midnight(): number {
    if (this.midnightInternal) {
      return this.midnightInternal
    }
    return this.defaultMidnight()
  }

  private midnightInternal = 0

  /**
   * The timestamp when the execution started
   */
  started = 0

  /**
   * The timestamp when the execution ended
   */
  ended = 0

  /**
   * The execution logs for each iteration.
   */
  iterations: IProjectExecutionIteration[] = []

  constructor(input?: string | IProjectExecution) {
    let init: IProjectExecution
    if (typeof input === 'string') {
      init = JSON.parse(input)
    } else if (typeof input === 'object') {
      init = input
    } else {
      const now = Date.now()
      init = {
        kind: Kind,
        user: '',
        app: '',
        key: '',
        project: '',
        ended: 0,
        iterations: [],
        midnight: 0,
        started: now,
      }
    }
    this.new(init)
  }

  new(init: IProjectExecution): void {
    const { started = Date.now(), midnight, project, user, key, app, ended = started, iterations, parent } = init
    this.started = started
    this.ended = ended
    this.iterations = iterations.map((i) => structuredClone(i))
    if (key) {
      this.key = key
    } else {
      this.key = ''
    }
    if (app) {
      this.app = app
    } else {
      this.app = ''
    }
    if (midnight) {
      this.midnight = midnight
    }
    if (project) {
      this.project = project
    } else {
      this.project = ''
    }
    if (parent) {
      this.parent = parent
    } else {
      this.parent = ''
    }
    if (user) {
      this.user = user
    } else {
      this.user = ''
    }
  }

  toJSON(): IProjectExecution {
    const result: IProjectExecution = {
      kind: Kind,
      midnight: this.midnight,
      user: this.user,
      key: this.key,
      project: this.project,
      app: this.app,
      ended: this.ended,
      iterations: this.iterations.map((i) => structuredClone(i)),
      started: this.started,
    }
    if (this.parent) {
      result.parent = this.parent
    }
    return result
  }

  /**
   * @returns The default value for the midnight when the request was last updated.
   */
  defaultMidnight(): number {
    const d = new Date(this.started)
    d.setHours(0, 0, 0, 0)
    return d.getTime()
  }
}
