import type { Awaitable } from "@vueuse/core";
import type { ChartOptions, DeepPartial, HistogramData, IChartApi, ISeriesApi, LayoutOptions, SeriesDataItemTypeMap, SeriesType, Time } from "lightweight-charts";
import type { ThemeMode } from "./useTheme";
import { AreaSeries, BarSeries, BaselineSeries, CandlestickSeries, ColorType, createChart, HistogramSeries, LineSeries } from "lightweight-charts";
import { cloneDeep, mergeWith } from "lodash-es";

export type Series = "Area" | "Bar" | "Baseline" | "Candlestick" | "Histogram" | "Line";

export type TData = SeriesDataItemTypeMap[SeriesType];

export type WeightChartOptions = DeepPartial<ChartOptions>;

export type TradingViewData = (() => Awaitable<TData[]>) | MaybeRefOrGetter<TData[]>;

export interface VolumeData extends HistogramData {
  value: number;
  color?: string;
}

export interface TradingViewOptions<T = Series> {
  theme?: ThemeMode;
  type?: T;
  data?: TradingViewData;
  volumeData?: MaybeRefOrGetter<VolumeData[]>;
  weightChartOptions?: MaybeRefOrGetter<WeightChartOptions>;
  autosize?: boolean;
  showVolume?: boolean;
}

const lightThemeLayout: Partial<LayoutOptions> = {
  textColor: "black",
  background: { type: ColorType.Solid, color: "#fff" },
};

const darkThemeLayout: Partial<LayoutOptions> = {
  textColor: "white",
  background: { type: ColorType.Solid, color: "#000" },
};

const initializeOptions: Required<TradingViewOptions> = {
  theme: "dark",
  type: "Candlestick",
  data: [],
  volumeData: [],
  weightChartOptions: {
    width: 400,
    height: 300,
  },
  autosize: true,
  showVolume: true,
};

function getChartSeriesDefinition(type: Series) {
  switch (type) {
    case "Area":
      return AreaSeries;
    case "Bar":
      return BarSeries;
    case "Baseline":
      return BaselineSeries;
    case "Candlestick":
      return CandlestickSeries;
    case "Histogram":
      return HistogramSeries;
    case "Line":
      return LineSeries;
    default:
      return CandlestickSeries;
  }
}

const { isDark } = useTheme();

export function useTradingView(target: MaybeRefOrGetter<HTMLElement | null>, options?: TradingViewOptions) {
  const opts: Required<TradingViewOptions> = mergeWith(cloneDeep(initializeOptions), cloneDeep(options));
  const chart = ref<IChartApi | null>(null);
  const chartSeriesDefinition = getChartSeriesDefinition(opts.type);
  const chartEl = ref<HTMLElement | null>(null);
  const series = ref<ISeriesApi<SeriesType> | null>(null);
  const volumeSeries = ref<ISeriesApi<"Histogram"> | null>(null);

  function fitContent() {
    chart.value?.timeScale().fitContent();
  }

  function resize() {
    if (!chart.value || !chartEl.value)
      return;
    const dimensions = chartEl.value.getBoundingClientRect();
    chart.value.resize(dimensions.width, dimensions.height);
  }

  function setData(data: TradingViewData) {
    if (isRef(data)) {
      series.value?.setData(toValue(data));
    }
    else if (isFunction(data)) {
      const result = data();
      if (isPromise(result)) {
        result.then((data) => {
          series.value?.setData(data);
          fitContent();
        }).catch((err) => {
          console.error("Failed to load trading view data:", err);
        });
      }
      else {
        series.value?.setData(result);
      }
    }
    else {
      series.value?.setData(toValue(data));
    }
  }

  function setVolumeData(data: MaybeRefOrGetter<VolumeData[]>) {
    if (!volumeSeries.value)
      return;
    const volumeData = toValue(data);
    volumeSeries.value.setData(volumeData);
  }

  function changeTheme(theme: ThemeMode) {
    if (!chart.value)
      return;
    const layout = theme === "dark" ? darkThemeLayout : lightThemeLayout;
    chart.value.applyOptions({ layout });
  }

  tryOnMounted(() => {
    const el = unrefElement(target);
    if (!el)
      return;
    chartEl.value = el;

    const chartOptions = toValue(opts.weightChartOptions);
    chart.value = createChart(el, chartOptions);
    series.value = chart.value.addSeries(chartSeriesDefinition, {
      priceFormat: {
        type: "price",
        precision: 1,
      },
    });

    // 添加成交量副图
    if (opts.showVolume) {
      volumeSeries.value = chart.value.addSeries(HistogramSeries, {
        priceFormat: {
          type: "volume",
        },
        priceScaleId: "", // 设置为右侧价格轴
      });

      // 配置成交量图表在底部
      chart.value.priceScale("").applyOptions({
        scaleMargins: {
          top: 0.8,
          bottom: 0,
        },
      });

      // 设置成交量数据
      if (opts.volumeData) {
        setVolumeData(opts.volumeData);
      }
    }

    watch(isDark, (dark) => {
      changeTheme(dark ? "dark" : "light");
    }, { immediate: true });

    setData(opts.data);
    fitContent();

    if (isRef(opts.data)) {
      watch(opts.data, (newData) => {
        setData(newData);
      }, { deep: true });
    }

    if (isRef(opts.volumeData)) {
      watch(opts.volumeData, (newData) => {
        setVolumeData(newData);
      }, { deep: true });
    }

    if (opts.autosize) {
      useTimeoutFn(() => {
        resize();
      }, 0);
      window.addEventListener("resize", resize);
    }
  });

  tryOnUnmounted(() => {
    chart.value?.remove();
    chart.value = null;
    window.removeEventListener("resize", resize);
  });

  watch(() => toValue(opts.weightChartOptions), (newOptions) => {
    if (!chart.value)
      return;
    chart.value.applyOptions(newOptions);
  }, { deep: true });

  return { chart, series, volumeSeries, fitContent, resize, setVolumeData };
}
