import { useCallback, useEffect, useRef, useState, type CSSProperties } from "react";
import { ScrollView, Text, View } from "@tarojs/components";
import { haptic } from "../../utils/haptics";
import "./index.scss";

export type ActionDrawerResult = {
  confirm: boolean;
  cancel: boolean;
};

export type ActionDrawerOptions = {
  title: string;
  content?: string;
  confirmText?: string;
  cancelText?: string;
  showCancel?: boolean;
  closeOnMask?: boolean;
  type?: "confirm" | "success" | "info" | "danger";
  confirmTone?: "primary" | "danger";
};

type DrawerState = Required<Pick<ActionDrawerOptions, "confirmText" | "cancelText" | "showCancel" | "closeOnMask" | "type" | "confirmTone">> &
  Omit<ActionDrawerOptions, "confirmText" | "cancelText" | "showCancel" | "closeOnMask" | "type" | "confirmTone"> & {
    closing: boolean;
  };

type DrawerTouchEvent = {
  touches?: Array<{ clientY: number }>;
  changedTouches?: Array<{ clientY: number }>;
  stopPropagation?: () => void;
};

function dragWithResistance(delta: number) {
  if (delta > 0) {
    return Math.min(220, delta < 120 ? delta * 0.78 : 94 + (delta - 120) * 0.36);
  }
  const upward = Math.abs(delta);
  return -Math.min(56, upward < 140 ? upward * 0.28 : 40 + (upward - 140) * 0.1);
}

function touchY(event: DrawerTouchEvent) {
  return event.touches?.[0]?.clientY ?? event.changedTouches?.[0]?.clientY ?? 0;
}

function normalizeOptions(options: ActionDrawerOptions): DrawerState {
  const type = options.type || "confirm";
  return {
    ...options,
    type,
    confirmTone: options.confirmTone || (type === "danger" ? "danger" : "primary"),
    confirmText: options.confirmText || (type === "success" ? "知道了" : "确认"),
    cancelText: options.cancelText || "取消",
    showCancel: options.showCancel ?? (type !== "success" && type !== "info"),
    closeOnMask: options.closeOnMask ?? true,
    closing: false
  };
}

export function useActionDrawer() {
  const [state, setState] = useState<DrawerState | null>(null);
  const [dragY, setDragY] = useState(0);
  const [expanded, setExpanded] = useState(false);
  const [isDragging, setIsDragging] = useState(false);
  const startY = useRef(0);
  const dragging = useRef(false);
  const resolveRef = useRef<((result: ActionDrawerResult) => void) | null>(null);
  const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  useEffect(() => {
    return () => {
      if (closeTimerRef.current) clearTimeout(closeTimerRef.current);
      resolveRef.current?.({ confirm: false, cancel: true });
      resolveRef.current = null;
    };
  }, []);

  const close = useCallback((result: ActionDrawerResult) => {
    haptic(result.confirm ? "medium" : "light");
    setDragY(0);
    setExpanded(false);
    setIsDragging(false);
    dragging.current = false;
    setState((current) => (current ? { ...current, closing: true } : current));
    if (closeTimerRef.current) clearTimeout(closeTimerRef.current);
    closeTimerRef.current = setTimeout(() => {
      setState(null);
      const resolve = resolveRef.current;
      resolveRef.current = null;
      resolve?.(result);
    }, 180);
  }, []);

  const showActionDrawer = useCallback((options: ActionDrawerOptions) => {
    if (closeTimerRef.current) clearTimeout(closeTimerRef.current);
    resolveRef.current?.({ confirm: false, cancel: true });
    setDragY(0);
    setExpanded(false);
    setIsDragging(false);
    const next = normalizeOptions(options);
    haptic(next.type === "success" ? "medium" : "light");
    setState(next);
    return new Promise<ActionDrawerResult>((resolve) => {
      resolveRef.current = resolve;
    });
  }, []);

  const startDrag = useCallback((event: DrawerTouchEvent) => {
    event.stopPropagation?.();
    haptic("light");
    dragging.current = true;
    setIsDragging(true);
    startY.current = touchY(event);
  }, []);

  const moveDrag = useCallback((event: DrawerTouchEvent) => {
    if (!dragging.current) return;
    event.stopPropagation?.();
    setDragY(dragWithResistance(touchY(event) - startY.current));
  }, []);

  const endDrag = useCallback((event: DrawerTouchEvent) => {
    if (!dragging.current) return;
    event.stopPropagation?.();
    dragging.current = false;
    setIsDragging(false);
    const delta = touchY(event) - startY.current;
    setDragY(0);
    if (expanded && delta > 64) {
      setExpanded(false);
      return;
    }
    if (!expanded && delta > 118) {
      close({ confirm: false, cancel: true });
      return;
    }
    if (delta < -52) {
      setExpanded(true);
    }
  }, [close, expanded]);

  const style: CSSProperties | undefined = dragY ? { transform: `translate3d(0, ${dragY}px, 0)` } : undefined;

  const actionDrawer = state ? (
    <View
      className={`action-drawer-mask ${state.closing ? "is-closing" : ""}`}
      catchMove
      onClick={() => {
        if (state.closeOnMask) close({ confirm: false, cancel: true });
      }}
    >
      <View
        className={`action-drawer action-drawer--${state.type} ${expanded ? "expanded" : ""} ${isDragging ? "dragging" : ""}`}
        style={style}
        catchMove
        onClick={(event) => event.stopPropagation()}
      >
        <View className="action-drawer__drag-zone" onTouchStart={startDrag} onTouchMove={moveDrag} onTouchEnd={endDrag} onTouchCancel={endDrag}>
          <View className="action-drawer__handle" />
        </View>

        {state.type === "success" || state.type === "danger" ? (
          <View className="action-drawer__mark">
            <Text>{state.type === "success" ? "✓" : "!"}</Text>
          </View>
        ) : null}

        <Text className="action-drawer__title">{state.title}</Text>
        {state.content ? (
          <ScrollView scrollY className="action-drawer__content-wrap">
            <Text className="action-drawer__content">{state.content}</Text>
          </ScrollView>
        ) : null}

        <View className={`action-drawer__actions ${state.showCancel ? "" : "is-single"}`}>
          {state.showCancel ? (
            <View className="action-drawer__btn action-drawer__btn--cancel" onClick={() => close({ confirm: false, cancel: true })}>
              <Text>{state.cancelText}</Text>
            </View>
          ) : null}
          <View
            className={`action-drawer__btn action-drawer__btn--confirm action-drawer__btn--${state.confirmTone}`}
            onClick={() => close({ confirm: true, cancel: false })}
          >
            <Text>{state.confirmText}</Text>
          </View>
        </View>
      </View>
    </View>
  ) : null;

  return { showActionDrawer, actionDrawer };
}
