import crypto from 'node:crypto';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { fetch as undiciFetch } from 'undici';
import { buildPublicUrl, PUBLISH_ROOT_DIR, PUBLIC_ZONE_DIR } from './user-publish.mjs';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

const DEFAULT_WECHAT_MEDIA_URL = 'https://api.weixin.qq.com/cgi-bin/media/get';
const DEFAULT_MAX_IMAGE_BYTES = 10 * 1024 * 1024;
const ALLOWED_IMAGE_MIME_TYPES = new Map([
  ['image/jpeg', 'jpg'],
  ['image/png', 'png'],
  ['image/webp', 'webp'],
  ['image/gif', 'gif'],
]);

function resolveImageExtension(contentType = '', fallbackUrl = '') {
  const normalized = String(contentType ?? '')
    .split(';')[0]
    .trim()
    .toLowerCase();
  if (ALLOWED_IMAGE_MIME_TYPES.has(normalized)) {
    return {
      mimeType: normalized,
      extension: ALLOWED_IMAGE_MIME_TYPES.get(normalized),
    };
  }
  const ext = path.extname(String(fallbackUrl ?? '').split('?')[0]).replace(/^\./, '').toLowerCase();
  if (ext === 'jpg' || ext === 'jpeg') return { mimeType: 'image/jpeg', extension: 'jpg' };
  if (ext === 'png') return { mimeType: 'image/png', extension: 'png' };
  if (ext === 'webp') return { mimeType: 'image/webp', extension: 'webp' };
  if (ext === 'gif') return { mimeType: 'image/gif', extension: 'gif' };
  return null;
}

function ensureImageWithinLimit(buffer, maxBytes) {
  if (!Buffer.isBuffer(buffer) || buffer.length === 0) {
    throw new Error('微信图片内容为空');
  }
  if (buffer.length > maxBytes) {
    throw new Error(`图片超过大小限制（${maxBytes} bytes）`);
  }
}

export async function downloadTemporaryMedia(accessToken, mediaId, { wechatFetch = undiciFetch } = {}) {
  if (!accessToken) throw new Error('缺少微信 access_token');
  if (!mediaId) throw new Error('缺少微信 mediaId');
  const url = new URL(DEFAULT_WECHAT_MEDIA_URL);
  url.searchParams.set('access_token', accessToken);
  url.searchParams.set('media_id', mediaId);
  const response = await wechatFetch(url.toString(), {
    method: 'GET',
    headers: { Accept: '*/*' },
  });
  if (!response.ok) {
    const text = await response.text().catch(() => '');
    throw new Error(text || `微信临时素材下载失败 (${response.status})`);
  }
  const contentType = response.headers.get('content-type') || '';
  const buffer = Buffer.from(await response.arrayBuffer());
  return { buffer, contentType };
}

export function buildWechatImagePublicUrl({
  publicBaseUrl,
  publishKey,
  filename,
  publicBasePath = `${PUBLIC_ZONE_DIR}/wechat-mp`,
}) {
  if (!publicBaseUrl) throw new Error('缺少图片公网基础地址');
  if (!publishKey) throw new Error('缺少用户 publish key');
  if (!filename) throw new Error('缺少图片文件名');
  return buildPublicUrl(publicBaseUrl, publishKey, `${publicBasePath}/${filename}`);
}

export async function persistWechatImage(
  {
    userId,
    appId,
    openid,
    msgId,
    mediaId,
    picUrl,
    publicBaseUrl,
    maxImageBytes = DEFAULT_MAX_IMAGE_BYTES,
  },
  {
    wechatFetch = undiciFetch,
    accessToken,
    h5Root = __dirname,
  } = {},
) {
  if (!userId) throw new Error('缺少 userId');
  const publishDir = path.join(h5Root, PUBLISH_ROOT_DIR, String(userId), PUBLIC_ZONE_DIR, 'wechat-mp');
  fs.mkdirSync(publishDir, { recursive: true });

  let source = 'wechat_media';
  let buffer;
  let contentType = '';

  if (mediaId && accessToken) {
    try {
      const downloaded = await downloadTemporaryMedia(accessToken, mediaId, { wechatFetch });
      buffer = downloaded.buffer;
      contentType = downloaded.contentType;
    } catch (error) {
      if (!picUrl) throw error;
    }
  }

  if (!buffer && picUrl) {
    source = 'wechat_pic_url';
    const response = await wechatFetch(picUrl, {
      method: 'GET',
      headers: { Accept: 'image/*,*/*;q=0.8' },
    });
    if (!response.ok) {
      const text = await response.text().catch(() => '');
      throw new Error(text || `微信图片下载失败 (${response.status})`);
    }
    contentType = response.headers.get('content-type') || contentType;
    buffer = Buffer.from(await response.arrayBuffer());
  }

  ensureImageWithinLimit(buffer, maxImageBytes);
  const resolved = resolveImageExtension(contentType, picUrl);
  if (!resolved) {
    throw new Error(`暂不支持的图片类型：${contentType || 'unknown'}`);
  }

  const timestamp = Date.now();
  const hash = crypto.createHash('sha1').update(buffer).digest('hex').slice(0, 12);
  const fileBase = [appId || 'wx', openid || 'openid', msgId || timestamp, mediaId || hash]
    .filter(Boolean)
    .join('-')
    .replace(/[^a-zA-Z0-9._-]+/g, '_')
    .slice(0, 120);
  const filename = `${fileBase}.${resolved.extension}`;
  const absolutePath = path.join(publishDir, filename);
  fs.writeFileSync(absolutePath, buffer);

  return {
    absolutePath,
    bytes: buffer.length,
    contentType: resolved.mimeType,
    filename,
    publicUrl: buildWechatImagePublicUrl({
      publicBaseUrl,
      publishKey: String(userId),
      filename,
    }),
    source,
  };
}
