import type { CurrentUser, Env, SiteSettings } from '../env';
import { extensionFromMime, isImageMime, isVideoMime } from '../utils/image';
import { randomToken, ulid } from '../utils/id';

type UploadKind = 'image' | 'video' | 'avatar' | 'site';

interface UploadMeta {
  key: string;
  kind: UploadKind;
  userId: string;
  size: number;
  mime: string;
  expiresAt: number;
}

function prefixForKind(kind: UploadKind): string {
  if (kind === 'video') return 'videos';
  if (kind === 'avatar') return 'avatars';
  if (kind === 'site') return 'site';
  return 'images';
}

export function validateUpload(kind: UploadKind, size: number, mime: string, settings: SiteSettings): void {
  if (kind === 'image' || kind === 'avatar' || kind === 'site') {
    if (!isImageMime(mime)) throw new Error('不支持的图片格式');
    if (size > settings.upload_max_image_mb * 1024 * 1024) throw new Error(`图片不能超过 ${settings.upload_max_image_mb}MB`);
    return;
  }
  if (!isVideoMime(mime)) throw new Error('不支持的视频格式');
  if (size > settings.upload_max_video_mb * 1024 * 1024) throw new Error(`视频不能超过 ${settings.upload_max_video_mb}MB`);
}

export async function signUpload(
  env: Env['Bindings'],
  settings: SiteSettings,
  user: CurrentUser,
  input: { kind: UploadKind; filename: string; size: number; mime: string },
  origin: string
): Promise<{ key: string; putUrl: string; headers: Record<string, string>; expiresAt: number }> {
  validateUpload(input.kind, input.size, input.mime, settings);
  const ext = extensionFromMime(input.mime, input.filename);
  const key = `${prefixForKind(input.kind)}/${user.id}/${ulid()}.${ext}`;
  const token = randomToken(32);
  const expiresAt = Math.floor(Date.now() / 1000) + 300;
  const meta: UploadMeta = {
    key,
    kind: input.kind,
    userId: user.id,
    size: input.size,
    mime: input.mime,
    expiresAt
  };
  await env.KV.put(`upload:${token}`, JSON.stringify(meta), { expirationTtl: 300 });
  return {
    key,
    putUrl: `${origin}/api/uploads/direct/${encodeURIComponent(token)}`,
    headers: {
      'Content-Type': input.mime,
      'X-Upload-Size': String(input.size)
    },
    expiresAt
  };
}

export async function putSignedUpload(env: Env['Bindings'], token: string, request: Request): Promise<UploadMeta> {
  const meta = await env.KV.get<UploadMeta>(`upload:${token}`, 'json');
  if (!meta) throw new Error('上传链接已过期');
  const contentType = request.headers.get('content-type') || '';
  const contentLength = Number(request.headers.get('content-length') || request.headers.get('x-upload-size') || '0');
  if (contentType.split(';')[0].toLowerCase() !== meta.mime.toLowerCase()) throw new Error('上传类型不匹配');
  if (contentLength && contentLength !== meta.size) throw new Error('上传大小不匹配');
  await env.R2.put(meta.key, request.body, {
    httpMetadata: { contentType: meta.mime },
    customMetadata: {
      kind: meta.kind,
      userId: meta.userId
    }
  });
  await env.KV.delete(`upload:${token}`);
  return meta;
}

export async function confirmUpload(env: Env['Bindings'], key: string): Promise<{ key: string; size: number; uploaded: boolean }> {
  const object = await env.R2.head(key);
  if (!object) throw new Error('文件不存在或未上传完成');
  return { key, size: object.size, uploaded: true };
}
