import { useEffect, useRef, useState } from 'react';
import { uploadFileToOss, type OssMediaType } from '../lib/upload';
import { enqueueUpload } from '../lib/upload-lock';
import { formatChooseImageFailMessage } from '@dukang/weixin-sdk';
import { isWechatEnv, weixinSdk } from '../lib/weixin';
import { toastError } from '../lib/toast';

type OssUploadFieldProps = {
  value?: string;
  onChange?: (url: string) => void;
  bizType: string;
  mediaType?: OssMediaType;
  accept?: string;
  wide?: boolean;
  compact?: boolean;
  label?: string;
  /** 兼容现有调用：选图不再依赖 openId 绑定 */
  wechatReady?: boolean;
  onWechatReadyChange?: (ready: boolean) => void;
};

function isCancelError(msg: string): boolean {
  return /cancel|取消/i.test(msg);
}

function formatWechatUploadError(e: unknown): string {
  const msg = e instanceof Error ? e.message : '无法打开相册';
  const formatted = formatChooseImageFailMessage(msg);
  if (formatted) return formatted;
  if (/invalid signature/i.test(msg)) {
    return '微信 JSSDK 签名校验失败：请确认公众号已配置 JS 接口安全域名，并刷新页面后重试';
  }
  return msg;
}

function acceptsImages(accept: string) {
  return accept.includes('image');
}

export default function OssUploadField({
  value,
  onChange,
  bizType,
  mediaType = 'IMAGE',
  accept,
  wide,
  compact,
  label,
}: OssUploadFieldProps) {
  const inputRef = useRef<HTMLInputElement>(null);
  const pickingRef = useRef(false);
  const [uploading, setUploading] = useState(false);
  const [error, setError] = useState('');
  const [showAlbumFallback, setShowAlbumFallback] = useState(false);

  function showUploadError(text: string) {
    setError(text);
    toastError(text);
  }

  const resolvedAccept =
    accept ?? (mediaType === 'VIDEO' ? 'video/*' : mediaType === 'FILE' ? 'image/*,.pdf' : 'image/*');
  const inWechat = isWechatEnv();
  const useWechatPicker =
    inWechat && (mediaType === 'IMAGE' || (mediaType === 'FILE' && acceptsImages(resolvedAccept)));

  useEffect(() => {
    if (!useWechatPicker) return;
    // 仅预热，勿在每次点击时 reset，否则取消后再点常无法调起
    void weixinSdk.init().catch(() => {
      /* 点击上传时会再次初始化 */
    });
  }, [useWechatPicker]);

  async function persistUpload(file: File) {
    if (!file.size) {
      showUploadError('图片读取失败，请重新选择');
      return;
    }
    const result = await uploadFileToOss(file, { bizType, mediaType });
    onChange?.(result.url);
  }

  async function uploadSelectedFile(file: File) {
    setUploading(true);
    setError('');
    try {
      await enqueueUpload(() => persistUpload(file));
    } catch (e) {
      showUploadError(e instanceof Error ? e.message : '上传失败');
    } finally {
      setUploading(false);
      if (inputRef.current) inputRef.current.value = '';
    }
  }

  async function pickWechatImage() {
    if (pickingRef.current || uploading) return;
    pickingRef.current = true;
    setError('');
    try {
      // 不要每次 reset：会打断 JSSDK，取消后再点经常无法调起相机/相册
      await weixinSdk.init();
      const files = await weixinSdk.chooseImages({
        count: 1,
        sourceType: ['album', 'camera'],
      });
      // 取消或未选图：直接结束，允许再次点击
      if (!files?.length) return;

      setUploading(true);
      try {
        // 仅串行化实际上传，选图本身不占上传锁，避免取消后锁态异常
        await enqueueUpload(() => persistUpload(files[0]!));
      } finally {
        setUploading(false);
      }
    } catch (e) {
      const msg = e instanceof Error ? e.message : '无法打开相册';
      if (isCancelError(msg)) return;
      throw e;
    } finally {
      pickingRef.current = false;
    }
  }

  async function pickFile() {
    if (uploading || pickingRef.current) return;
    setError('');

    if (useWechatPicker) {
      try {
        await pickWechatImage();
      } catch (e) {
        const msg = e instanceof Error ? e.message : '无法打开相册';
        if (isCancelError(msg)) return;
        const formatted = formatWechatUploadError(e);
        setError(`${formatted}，可改从系统相册选择`);
        setShowAlbumFallback(true);
        inputRef.current?.click();
      }
      return;
    }

    inputRef.current?.click();
  }

  const isImage = mediaType === 'IMAGE' && value;
  const isFile = mediaType === 'FILE' && value;
  const busy = uploading;
  const pickerLabel = label ?? (useWechatPicker ? '拍照 / 从相册选择' : '点击上传');

  const triggerProps = {
    type: 'button' as const,
    disabled: busy,
    onClick: () => void pickFile(),
  };

  return (
    <div className="partner-oss-upload">
      <input
        ref={inputRef}
        type="file"
        accept={resolvedAccept}
        className="partner-oss-upload-input"
        disabled={busy}
        onChange={(e) => {
          const file = e.target.files?.[0];
          if (file) {
            setShowAlbumFallback(false);
            void uploadSelectedFile(file);
          }
        }}
      />
      {isImage ? (
        <button {...triggerProps} className={`partner-upload-preview${wide ? ' partner-upload-preview--wide' : ''}`}>
          <img src={value} alt={label ?? '已上传'} />
          <span className="partner-upload-preview-mask">
            <span className="material-symbols-outlined">{busy ? 'hourglass_top' : 'edit'}</span>
            <span>{uploading ? '上传中…' : '更换'}</span>
          </span>
        </button>
      ) : isFile ? (
        <button {...triggerProps} className="partner-upload-file">
          <div className="partner-bills-icon" style={{ background: '#ffb3ae' }}>
            <span className="material-symbols-outlined text-primary">description</span>
          </div>
          <div style={{ textAlign: 'left', flex: 1 }}>
            <span className="text-primary" style={{ fontWeight: 700, display: 'block' }}>已上传合同</span>
            <span className="label-md text-muted">{uploading ? '上传中…' : '点击更换'}</span>
          </div>
        </button>
      ) : (
        <button
          {...triggerProps}
          className={`partner-upload-dashed${wide ? ' partner-upload-dashed--wide' : ''}${compact ? ' partner-upload-dashed--compact' : ''}`}
        >
          <span className="material-symbols-outlined text-primary" style={{ fontSize: compact ? 28 : 36 }}>
            {busy ? 'hourglass_top' : 'add_a_photo'}
          </span>
          <span className="text-primary" style={{ fontWeight: 500 }}>
            {uploading ? '上传中…' : pickerLabel}
          </span>
        </button>
      )}
      {showAlbumFallback && useWechatPicker && (
        <button
          type="button"
          className="partner-btn-outline"
          style={{ marginTop: 8, width: '100%' }}
          disabled={busy}
          onClick={() => inputRef.current?.click()}
        >
          从系统相册选择
        </button>
      )}
      {error && <p className="partner-form-error" role="alert">{error}</p>}
    </div>
  );
}
