/**
 * 模块：HeadHandler
 * 功能：处理TUS协议的HEAD请求，用于获取上传文件的状态信息
 * 使用场景：在文件分片上传过程中，客户端需要定期查询上传进度时使用
 */
import { CancellationContext, ERRORS, Upload, Metadata } from '../utils'
import { BaseHandler } from './BaseHandler'
import type http from 'node:http'

/**
 * HeadHandler类
 * 核心功能：处理TUS协议的HEAD请求，返回文件上传的元数据和进度信息
 * 设计模式：继承自BaseHandler，采用模板方法模式
 * 使用示例：
 * const handler = new HeadHandler(store, options)
 * await handler.send(req, res, context)
 */
export class HeadHandler extends BaseHandler {
  /**
   * 处理HEAD请求的核心方法
   * @param req HTTP请求对象
   * @param res HTTP响应对象
   * @param context 取消操作的上下文
   * @returns 返回HTTP响应
   * @throws ERRORS.FILE_NOT_FOUND 文件ID不存在时抛出
   * @throws ERRORS.FILE_NO_LONGER_EXISTS 文件已过期时抛出
   */
  async send(
    req: http.IncomingMessage,
    res: http.ServerResponse,
    context: CancellationContext
  ) {
    // 从请求中提取文件ID
    const id = this.getFileIdFromRequest(req)
    if (!id) {
      throw ERRORS.FILE_NOT_FOUND
    }

    // 执行自定义的请求预处理逻辑
    if (this.options.onIncomingRequest) {
      await this.options.onIncomingRequest(req, res, id)
    }

    // 获取文件锁，防止并发操作
    const lock = await this.acquireLock(req, id, context)

    let file: Upload
    try {
      // 从存储中获取文件上传信息
      file = await this.store.getUpload(id)
    } finally {
      // 无论成功与否，都释放锁
      await lock.unlock()
    }

    // 检查文件是否已过期
    const now = new Date()
    if (
      this.store.hasExtension('expiration') &&
      this.store.getExpiration() > 0 &&
      file.creation_date &&
      now > new Date(new Date(file.creation_date).getTime() + this.store.getExpiration())
    ) {
      throw ERRORS.FILE_NO_LONGER_EXISTS
    }

    // 设置响应头，防止缓存
    res.setHeader('Cache-Control', 'no-store')
    // 返回当前上传偏移量
    res.setHeader('Upload-Offset', file.offset)

    // 处理文件大小信息
    if (file.sizeIsDeferred) {
      // 如果文件大小未知，设置延迟长度标志
      res.setHeader('Upload-Defer-Length', '1')
    } else {
      // 如果文件大小已知，返回实际大小
      res.setHeader('Upload-Length', file.size as number)
    }

    // 处理文件元数据
    if (file.metadata !== undefined) {
      // 将元数据转换为字符串格式返回
      res.setHeader('Upload-Metadata', Metadata.stringify(file.metadata) as string)
    }

    // 结束响应
    return res.end()
  }
}
