// import crypto from 'node:crypto'
// import { Config } from './config'
// import { TYPE, AcceptedValue, ConfigOptions } from './types'
// import { UrlSafeBase64 } from '@/base64'
// import { sha256 } from '@/hash'

// export class Factory {
//   private separator = '\x1f'
//   private encoding: BufferEncoding = 'utf8'
//   public config: Config = new Config()
//   public lastConfig: Config | null = null

//   constructor(config?: ConfigOptions | Config) {
//     config && this.setConfig(config)
//   }

//   public same(): this {
//     this.config.entropy = 0
//     return this.setConfig(this.config)
//   }

//   public unique(): this {
//     this.config.entropy = 4
//     return this.setConfig(this.config)
//   }

//   public setConfig(config: ConfigOptions | Config): this {
//     if (!(config instanceof Config)) config = new Config(config)
//     this.config = Object.assign(new Config(), config)
//     return this
//   }

//   public onceConfig(config: ConfigOptions | Config): this {
//     if (!(config instanceof Config)) config = new Config(config)
//     this.lastConfig = this.config
//     this.config = Object.assign(new Config(), config)
//     return this
//   }

//   public onceKey(secret: string): this {
//     this.lastConfig = Object.assign(new Config(), this.config)
//     this.config.key = secret
//     return this
//   }

//   private maybeRestoreConfig(): this {
//     if (this.lastConfig !== null) {
//       this.config = Object.assign(new Config(), this.lastConfig)
//       this.lastConfig = null
//     }
//     return this
//   }

//   private validateConfig(): void {
//     const key = this.config.key
//     if (typeof key !== 'string' || !key.trim())
//       throw new Error('Secret key is required for use cripta.')
//   }

//   public encode(data: AcceptedValue): string {
//     this.validateConfig()

//     const entropyInt = this.config.getInt('entropy')
//     const entropy = entropyInt ? crypto.randomBytes(entropyInt).toString('binary') : ''
//     const payload = this.toText(data)

//     const encoded = this.baseEncode(this.cipher(
//       payload, this.forgeKey(entropy)
//     ) + entropy)

//     this.maybeRestoreConfig()
//     return encoded
//   }

//   public decode(data: string): AcceptedValue {
//     this.validateConfig()

//     const binary = this.baseDecode(data)
//     const eLength = this.config.getInt('entropy')
//     const entropy = binary.slice(-eLength)

//     const decoded = this.convert(this.cipher(
//       // binary.substring(0, binary.length - eLength),
//       binary.slice(0, -eLength),
//       this.forgeKey(entropy)
//     ))

//     this.maybeRestoreConfig()
//     return decoded
//   }

//   private convert(value: string): AcceptedValue {
//     const separatorIndex = value.indexOf(this.separator)
//     if (separatorIndex !== -1) {
//       const typeStr = value.substring(0, separatorIndex)
//       const typeNum = parseInt(typeStr, 10)
//       const data = value.substring(separatorIndex + 1)

//       switch (typeNum) {
//         case TYPE.null: return null
//         case TYPE.boolean: return data === 'true' || data === '1'
//         case TYPE.string: return data
//         case TYPE.int: return parseInt(data, 10)
//         case TYPE.float: return parseFloat(data)
//         case TYPE.bigint: return BigInt(data)
//         case TYPE.array:
//         case TYPE.object:
//           try {
//             return JSON.parse(data)
//           } catch {
//             return null
//           }
//         case TYPE.symbol: return Symbol.for(data)
//         case TYPE.undefined: return undefined
//       }
//     }

//     try {
//       return JSON.parse(value)
//     } catch {
//       return value
//     }
//   }

//   private toText(value: AcceptedValue): string {
//     if (value === null)
//       return `${TYPE.null}${this.separator}`

//     if (value === undefined)
//       return `${TYPE.undefined}${this.separator}`

//     const type = typeof value

//     if (type === 'boolean')
//       return `${TYPE.boolean}${this.separator}${value ? 'true' : 'false'}` // encurtar para 1/0

//     if (type === 'string')
//       return `${TYPE.string}${this.separator}${value}`

//     if (type === 'number')
//       return `${Number.isInteger(value) ? TYPE.int : TYPE.float}${this.separator}${value}`

//     if (type === 'bigint')
//       return `${TYPE.bigint}${this.separator}${value?.toString()}`

//     if (type === 'symbol')
//       // @ts-ignore
//       return `${TYPE.symbol}${this.separator}${Symbol.keyFor(value) ?? value?.toString()}`

//     if (Array.isArray(value))
//       return `${TYPE.array}${this.separator}${JSON.stringify(value)}`

//     if (type === 'object')
//       return `${TYPE.object}${this.separator}${JSON.stringify(value)}`

//     return ''
//   }

//   private cipher(str: string | null | undefined, key: string = ''): string {
//     if (!str || !key || !str.length) return ''

//     const result: string[] = new Array
//     let dataLength = str.length - 1
//     const keyLength = key.length - 1

//     do {
//       result[dataLength] = String.fromCharCode(str.charCodeAt(dataLength) ^ key.charCodeAt(dataLength % keyLength))
//       // result.push(String.fromCharCode(str.charCodeAt(dataLength) ^ key.charCodeAt(dataLength % keyLength)))
//     } while (dataLength--)

//     return result.join('')
//     // return result.reverse().join('')
//   }

//   private maybeUseAlphabet(data: string, from?: string, to?: string): string {
//     if (!data || typeof data !== 'string' || !from || !to || from === to)
//       return data

//     return this.strtr(data, from, to)
//   }

//   private strtr(str: string, from: string, to: string): string {
//     let result = ''
//     for (let i = 0; i < str.length; i++) {
//       const char = str[i]
//       const index = from.indexOf(char)
//       result += index !== -1 && index < to.length ? to[index] : char
//     }
//     return result
//   }

//   private forgeKey(entropy: string = ''): string {
//     return sha256(this.config.key + entropy, 'base64url')
//     // return sha256(this.config.key + entropy, 'binary').toString('binary')
//   }

//   baseEncode(data: string | Buffer): string {
//     return this.maybeUseAlphabet(
//       UrlSafeBase64.encode(data),
//       this.config.baseAlphabet,
//       this.config.alphabet
//     )
//   }

//   baseDecode(data: string): string {
//     return UrlSafeBase64.decode(this.maybeUseAlphabet(
//       data,
//       this.config.alphabet,
//       this.config.baseAlphabet
//     ))
//   }
// }