/* eslint-disable @typescript-eslint/unified-signatures */
import { SameSiteValue } from '../../../../cookies/CookieParser.js'
import { HttpStep, IHttpStep } from '../../HttpStep.js'

export const SetCookieStepKind = 'HttpAction#SetCookie'

export interface ISetCookieStepInit {
  /**
   * The name of the cookie
   */
  name: string
  /**
   * The URL associated with the cookie. When not set it uses the request URL or the request URL of the last redirect.
   */
  url?: string
  /**
   * The cookie expiration time. It can be a valid cookie date or a string representing a relative time to "now"
   * like `4d`, `600s`, etc.
   */
  expires?: string
  /**
   * Whether the cookie is host only
   */
  hostOnly?: boolean
  /**
   * Whether the cookie is HTTP only
   */
  httpOnly?: boolean
  /**
   * Whether the cookie is HTTPS only
   */
  secure?: boolean
  /**
   * Whether the cookie is a session cookie
   */
  session?: boolean
  /**
   * The SameSite parameter of the cookie.
   * https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#creating_cookies
   */
  sameSite?: SameSiteValue
}

/**
 * A step that allows to set a cookie with the value returned by a previous step.
 */
export interface ISetCookieStep extends IHttpStep, ISetCookieStepInit {
  kind: typeof SetCookieStepKind
}

export class SetCookieStep extends HttpStep {
  override kind = SetCookieStepKind

  /**
   * The name of the cookie
   */
  name = ''

  /**
   * The URL associated with the cookie.
   * When not set it uses the request URL or the request URL of the last redirect.
   */
  url?: string

  /**
   * The cookie expiration time. It can be a valid cookie date or a string representing a relative time to "now"
   * like `4d`, `600s`, etc.
   */
  expires?: string

  /**
   * Whether the cookie is host only
   */
  hostOnly?: boolean

  /**
   * Whether the cookie is HTTP only
   */
  httpOnly?: boolean

  /**
   * Whether the cookie is HTTPS only
   */
  secure?: boolean

  /**
   * Whether the cookie is a session cookie
   */
  session?: boolean

  /**
   * The SameSite parameter of the cookie.
   * https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#creating_cookies
   */
  sameSite?: SameSiteValue

  /**
   * Creates the step from values.
   * @param name The name of the variable to set
   * @param url Optional URL of the cookie to set.
   */
  constructor(name: string, url?: string)

  /**
   * Creates the step from serialized schema.
   * @param init The serialized step values.
   */
  constructor(init: ISetCookieStepInit)

  /**
   * Creates an empty step.
   */
  constructor()

  constructor(nameOrInit?: string | ISetCookieStepInit, url?: string) {
    super()
    if (!nameOrInit) {
      return
    }
    if (typeof nameOrInit === 'object') {
      const typed = nameOrInit as ISetCookieStepInit
      this.new({ ...typed, kind: SetCookieStepKind })
    } else if (typeof nameOrInit === 'string') {
      this.new({
        kind: SetCookieStepKind,
        name: nameOrInit,
        enabled: true,
        url,
      })
    }
  }

  override new(init: ISetCookieStep): void {
    super.new(init)
    this.kind = SetCookieStepKind
    this.name = init.name
    if (init.url) {
      this.url = init.url
    } else {
      this.url = undefined
    }
    if (init.expires) {
      this.expires = init.expires
    } else {
      this.expires = undefined
    }
    if (typeof init.hostOnly === 'boolean') {
      this.hostOnly = init.hostOnly
    } else {
      this.hostOnly = undefined
    }
    if (typeof init.httpOnly === 'boolean') {
      this.httpOnly = init.httpOnly
    } else {
      this.httpOnly = undefined
    }
    if (typeof init.secure === 'boolean') {
      this.secure = init.secure
    } else {
      this.secure = undefined
    }
    if (typeof init.session === 'boolean') {
      this.session = init.session
    } else {
      this.session = undefined
    }
    if (typeof init.sameSite === 'boolean') {
      this.sameSite = init.sameSite
    } else {
      this.sameSite = undefined
    }
  }

  checkValidity(): boolean {
    const { name } = this
    return !!name
  }

  override toJSON(): ISetCookieStep {
    const result: ISetCookieStep = {
      ...super.toJSON(),
      kind: SetCookieStepKind,
      name: this.name,
    }
    if (this.url) {
      result.url = this.url
    }
    if (this.expires) {
      result.expires = this.expires
    }
    if (typeof this.hostOnly === 'boolean') {
      result.hostOnly = this.hostOnly
    }
    if (typeof this.httpOnly === 'boolean') {
      result.httpOnly = this.httpOnly
    }
    if (typeof this.secure === 'boolean') {
      result.secure = this.secure
    }
    if (typeof this.session === 'boolean') {
      result.session = this.session
    }
    if (typeof this.sameSite === 'boolean') {
      result.sameSite = this.sameSite
    }
    return result
  }
}
