// withHooks
import { doc, getFirestore, runTransaction } from '@react-native-firebase/firestore';
import { Canvas, Group, RoundedRect, Text, useFont } from '@shopify/react-native-skia';
import { EventButton } from 'esoftplay/cache/event/button/import';
import { EventHeader } from 'esoftplay/cache/event/header/import';
import { EventMessage } from 'esoftplay/cache/event/message/import';
import { LibBackground_task } from 'esoftplay/cache/lib/background_task/import';
import { LibCurl } from 'esoftplay/cache/lib/curl/import';
import { LibIcon } from 'esoftplay/cache/lib/icon/import';
import { LibNavigation } from 'esoftplay/cache/lib/navigation/import';
import { LibStyle } from 'esoftplay/cache/lib/style/import';
import { LibTextstyle } from 'esoftplay/cache/lib/textstyle/import';
import { LibToastProperty } from 'esoftplay/cache/lib/toast/import';
import { UseMap } from 'esoftplay/cache/use/map/import';
import esp from 'esoftplay/esp';
import useLazyState from 'esoftplay/lazy';
import useSafeState from 'esoftplay/state';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Dimensions, Pressable, ScrollView, View } from 'react-native';
import { TapGestureHandler, TapGestureHandlerStateChangeEvent } from 'react-native-gesture-handler';


export interface EventSeat_map_newArgs {

}
export interface EventSeat_map_newProps {

}

function getEventPath() {
  return "event" + (esp.isDebug("") ? "BBT" : "BBO")
}

const mainPath = [getEventPath(), "event_seat", "seat_index"]
export function clearHoldedSeats() {
  const app: any = esp.mod("firestore/index")().instance()
  const firestoreUser = esp.mod("firestore/index")().getUserData(app.name)
  esp.mod("firestore/index")().getCollectionIds(app, mainPath, [["uid", "==", firestoreUser?.uid], ["status", "==", "holding"]], [], (ids) => {
    if (ids?.length > 0)
      esp.mod("firestore/index")().deleteBatchDocument(app, mainPath, ids, () => {
      }, console.log)
  }, console.log)
}

export default function m(props: any): any {
  const { dataTicket } = LibNavigation.getArgsAll<any>(props)
  const qty = dataTicket?.qty

  const eventData = {
    event_id: dataTicket?.event_id,
    price_id: dataTicket?.selected_ticket?.price_id,
    ondate: dataTicket?.ondate || dataTicket?.selected_ticket?.list?.ondate
  }

  const app: any = esp.mod("firestore/index")().instance()
  const firestoreUser = esp.mod("firestore/index")().getUserData(app.name)

  const [, setHoldedSeats, getHoldedSeats] = useLazyState<string[]>([])
  const [, setLoadingSeats, getLoadingSeats] = useSafeState<string[]>([])

  const deviceWidth = Dimensions.get('window').width;
  const [scale, setScale] = useState(1);
  const [boundingBox, setBoundingBox] = useSafeState({ "x1": 1, "x2": 2, "y1": 1, "y2": 2 })
  const [data, setData, getData] = useSafeState<[number, number, string, number][]>([])
  const initialBoxSize = 30;
  const contentWidth = (boundingBox.x2 - (boundingBox.x1 - 1.1)) * initialBoxSize
  const [, setSelectedSeat, getSelectedSeat] = useSafeState<any>([])
  const [errBookedSeat, setErrBookedSeat] = useSafeState()

  // Scale boxSize so that contentWidth fits deviceWidth
  const scaleToFit = deviceWidth / contentWidth;
  const boxSize = initialBoxSize * scaleToFit;

  // Recalculate xs, ys, width, height with scaled boxSize
  const xsScaled = getData()?.map(([x]) => isNaN(x) ? 0 : (boxSize) + (x * boxSize));
  const ysScaled = getData()?.map(([_, y]) => isNaN(y) ? 0 : (boxSize) + (y * boxSize));

  const width = Math.max(deviceWidth, xsScaled.length && xsScaled.every(v => !isNaN(v)) ? Math.max(...xsScaled) + boxSize : boxSize * 2);
  const height = ysScaled.length && ysScaled.every(v => !isNaN(v)) ? Math.max(...ysScaled) + boxSize : boxSize * 2;


  // Preload all possible fonts at top level (to avoid render hook errors)
  const fontSizes = [boxSize * 0.35, boxSize * 0.30, boxSize * 0.27, boxSize * 0.25, boxSize * 0.20];
  const fonts = fontSizes.map(size => useFont(esp.assets('fonts/MonoSpace.ttf'), size));

  const getFontByLength = (length: number) => {
    if (length <= 2) return fonts[0];
    if (length == 3) return fonts[1];
    if (length == 4) return fonts[2];
    if (length == 5) return fonts[3];
    return fonts[4];
  };

  const getFontSizeByLength = (length: number) => {
    if (length <= 2) return fontSizes[0];
    if (length == 3) return fontSizes[1];
    if (length == 4) return fontSizes[2];
    if (length == 5) return fontSizes[3];
    return fontSizes[4];
  };


  // const size: any = {
  //   1: useFont(esp.assets('fonts/MonoSpace.ttf'), boxSize * 0.3),
  //   2: useFont(esp.assets('fonts/MonoSpace.ttf'), boxSize * 0.3),
  //   3: useFont(esp.assets('fonts/MonoSpace.ttf'), boxSize * 0.25),
  //   4: useFont(esp.assets('fonts/MonoSpace.ttf'), boxSize * 0.27),
  //   5: useFont(esp.assets('fonts/MonoSpace.ttf'), boxSize * 0.25),
  //   6: useFont(esp.assets('fonts/MonoSpace.ttf'), boxSize * 0.15),
  // }

  const handleTap = useCallback((event: TapGestureHandlerStateChangeEvent) => {
    if (event.nativeEvent.state !== 5) return;

    const x = event.nativeEvent.x / scale;
    const y = event.nativeEvent.y / scale;

    for (let i = 0; i < getData()?.length; i++) {
      const [sx, sy, seatName, status] = getData()?.[i];

      const xSize = (boxSize / 2) + (sx * boxSize);
      const ySize = (boxSize / 2) + (sy * boxSize);

      if (x >= xSize && x <= xSize + boxSize && y >= ySize && y <= ySize + boxSize) {
        if (status != 0) return;
        if (getLoadingSeats().includes(seatName)) return;

        const isSelected = getSelectedSeat().includes(seatName);

        const seat: any = getHoldedSeats().find((x: any) => x.id === seatName);
        const isHolded = !!seat;
        const isMine = seat?.uid === firestoreUser?.uid;

        if (isHolded && !isMine) {
          LibToastProperty.show(esp.lang("event/seat_map_new", "other_user"));
          return;
        }

        if (!isSelected && getSelectedSeat().length >= qty) {
          LibToastProperty.show(esp.lang("event/seat_map", "max_seat", qty));
          return;
        }

        const action = isSelected ? "release" : "hold";
        setSelectedSeat((prev: any) => {
          if (isSelected) {
            return prev.filter((s: string) => s !== seatName);
          } else {
            return [...prev, seatName];
          }
        });

        setLoadingSeats(prev => [...prev, seatName]);
        handleSelectedSeat(seatName, action)
          .then(() => { })
          .catch((err: any) => {
            // setSelectedSeat((prev: any) => {
            //   if (action === "hold") {
            //     return prev.filter((s: string) => s !== seatName);
            //   } else {
            //     return [...prev, seatName];
            //   }
            // });
            // LibToastProperty.show(err?.message || esp.lang("event/seat_map_new", "failed_sync"));
          })
          .finally(() => {
            setLoadingSeats(prev => prev.filter(s => s !== seatName));
          });

        return;
      }
    }
  }, [data, boxSize, scale, firestoreUser]);

  async function handleSelectedSeat(seatName: string, action?: "hold" | "release") {
    const pathKey = `${eventData?.event_id}_${eventData?.price_id}_${eventData?.ondate}_${seatName}`
    const path = [...mainPath, pathKey]
    const fixedPath = esp.mod("firestore/index")().castPathToString(path)

    try {
      await holdSeat(fixedPath, pathKey, action)
    } catch (error) {
      console.warn("Failed to hold seat:", error, firestoreUser.uid);
      throw error
    }
  }

  const cat_id = `${eventData?.price_id}_${eventData?.ondate}`
  async function holdSeat(path: string, pathKey: string, action?: "hold" | "release") {
    const uid = firestoreUser?.uid

    const db = getFirestore(app)
    const seatRef = doc(db, path);

    await runTransaction(db, async (tx) => {
      const snap = await tx.get(seatRef);
      const value = {
        status: "holding",
        id: pathKey,
        cat_id,
        uid,
        updated: Date.now(),
      }

      if (!snap.exists()) {
        tx.set(seatRef, value);
        return;
      }

      const data: any = snap.data();
      if (data.status === "holding" && data.uid === uid) {
        if (action === "release") {
          tx.update(seatRef, {
            status: "available"
          });
          return;
        } else {
          return;
        }
      }
      if (data.status === "available") {
        tx.update(seatRef, value);
        return;
      }
      throw new Error(esp.lang("event/seat_map_new", "seat_not_avail"));
    });
  }

  useEffect(() => {
    loadDataSeatmapBooked()
    return () => LibNavigation.cancelBackResult(LibNavigation.getResultKey(props))
  }, [])

  useEffect(() => {
    getAllHeldSeats()
    updateTimestamp()
    LibBackground_task.set("1", getAllHeldSeats, 2000)
    LibBackground_task.set("2", updateTimestamp, 3000)
    return () => {
      LibBackground_task.clear("1")
      LibBackground_task.clear("2")
    }
  }, [])

  function getAllHeldSeats() {
    esp.mod("firestore/index")().getCollectionWhere(app, mainPath, [
      ["cat_id", "==", cat_id],
      ["uid", "!=", firestoreUser?.uid],
      ["status", "==", "holding"],
    ], (docs) => {
      const seats = docs.map((d: any) => ({ ...d.data, id: d.id.split("_").pop() }));
      setHoldedSeats(seats)()
    }, console.warn)
  }

  function updateTimestamp() {
    esp.mod("firestore/index")().getCollectionIds(app, mainPath, [
      ["cat_id", "==", cat_id],
      ["uid", "==", firestoreUser?.uid],
      ["status", "==", "holding"],
    ], [], (ids) => {
      esp.mod("firestore/index")().updateBatchDocument(app, mainPath, ids,
        [{ key: "updated", value: Date.now() }],
        () => { },
        console.warn)
    }, console.warn)
  }

  function updateIndexByRes(data: any, res: any) {
    const resArr = res.split(",").map((item: any) => item.trim()); // biar aman dari spasi
    return data.map((row: any) => {
      if (resArr.includes(row[2])) {
        return [row[0], row[1], row[2], 3];
      }
      return row;
    });
  }

  function loadDataSeatmap(seatBooked: any) {
    new LibCurl("v3/event_seat", {
      event_id: dataTicket?.event_id,
      price_id: dataTicket?.selected_ticket?.price_id,
      ondate: dataTicket?.ondate || dataTicket?.selected_ticket?.list?.ondate
    }, (res, msg) => {

      setBoundingBox(res.metadata.bounding_box)
      let x = res.layout.split(';').map((item: any) => item.split(',')).map(([x, y, seatName, status]: any) => [Number(x), Number(y), seatName, Number(status)])
      let updated = updateIndexByRes(x, seatBooked)
      setData(updated)
    })
  }

  const holdedSeatsMap = useMemo(() => {
    const map: any = {};
    getHoldedSeats().forEach((x: any) => {
      map[x.id] = x.uid;
    });
    return map;
  }, [getHoldedSeats()]);

  function loadDataSeatmapBooked() {
    new LibCurl("v3/event_seat_booked", {
      event_id: dataTicket?.event_id,
      price_id: dataTicket?.selected_ticket?.price_id,
      ondate: dataTicket?.ondate || dataTicket?.selected_ticket?.list?.ondate
    }, (res, msg) => {
      loadDataSeatmap(res)
      setErrBookedSeat(undefined)

    }, (err) => {
      setErrBookedSeat(err?.message)
    })
  }

  if (errBookedSeat) {
    return (
      <View style={{ flex: 1, backgroundColor: LibStyle.colorBgGrey }}>
        <EventHeader title={esp.lang("event/seat_map", "header_title")} />
        <View style={{ flex: 1 }}>
          <EventMessage
            message={errBookedSeat}
            children={
              <EventButton
                label='Coba lagi'
                style={{ marginHorizontal: 15 }}
                onPress={() => {
                  loadDataSeatmapBooked()
                }}
              />
            }
          />
        </View>
      </View>
    )
  }

  return (
    <View key={scale} style={{ flex: 1, backgroundColor: LibStyle.colorBgGrey }} >
      <EventHeader title={esp.lang("event/seat_map", "header_title")} subtitle={dataTicket?.selected_ticket?.type} />
      <View style={{ flex: 1 }}>
        <View style={{ marginBottom: 5, }}>
          <ScrollView style={{ padding: 10, paddingLeft: 0, }} horizontal>
            <UseMap
              data={getLegends()}
              renderItem={(item) => (
                <View style={{ flexDirection: 'row', alignItems: 'center', marginLeft: 15, marginRight: 5 }} >
                  <View style={{ height: 20, width: 20, borderRadius: 2, borderWidth: 0.5, backgroundColor: item[0], marginRight: 8 }} />
                  <LibTextstyle textStyle='caption1' text={item[1]} />
                </View>
              )}
            />
          </ScrollView>
        </View>
        <ScrollView horizontal >
          <ScrollView >
            <TapGestureHandler onHandlerStateChange={handleTap}>
              <View>
                <Canvas
                  style={{
                    width: width * scale,
                    height: height * scale,
                    backgroundColor: LibStyle.colorBgGrey,

                  }}>
                  {
                    getData()?.map(([x, y, name, status], i) => {
                      let newName = name?.replace(/^.*#/, "")
                      const isSelected = getSelectedSeat()?.includes(name)
                      const uid = holdedSeatsMap[name];
                      const isHolded = !!uid;
                      const isMine = uid === firestoreUser?.uid;
                      const color = isSelected ? "#8EF67B" : (isHolded && !isMine) ? getColorByStatus(9) : getColorByStatus(status)
                      const xSize = (boxSize / 2) + (x * boxSize)
                      const ySize = (boxSize / 2) + (y * boxSize)

                      const xBSize = xSize - (boxSize * 0.05 / 2)
                      const yBSize = ySize - (boxSize * 0.05 / 2)

                      const fontSize = getFontSizeByLength(newName?.length);
                      const font = getFontByLength(newName?.length);

                      const textWidthApprox = fontSize * newName?.length * 0.6;
                      const textX = xSize + (boxSize - textWidthApprox) / 2;

                      return (
                        <Group key={i}>
                          <RoundedRect
                            r={(boxSize) * 0.155}
                            x={xBSize}
                            y={yBSize}
                            transform={[{ scale }]}
                            width={boxSize * 1.05}
                            height={boxSize * 1.05}
                            color={"#999"} />
                          <RoundedRect
                            x={xSize}
                            r={boxSize * 0.13}
                            y={ySize}
                            width={boxSize}
                            transform={[{ scale }]}
                            height={boxSize}
                            color={color} />
                          {name && font && (
                            <Text
                              x={textX}
                              y={(ySize) + boxSize * 0.60}
                              color={"#020202"}
                              text={newName}
                              transform={[{ scale }]}
                              font={font} />
                          )}
                        </Group>
                      )
                    })
                  }
                </Canvas>
              </View>
            </TapGestureHandler>
          </ScrollView>
        </ScrollView>
        <View style={{ flexDirection: 'row', marginHorizontal: 12, height: 40, borderColor: '#060606', borderWidth: 1, borderRadius: 5, alignItems: 'center' }} >
          <Pressable onPress={() => setScale((x) => x - 0.3)} style={{ height: 40, width: 40, alignItems: 'center', justifyContent: 'center' }} >
            <LibIcon.SimpleLineIcons name='magnifier-remove' />
          </Pressable>
          <Pressable onPress={() => setScale((x) => x + 0.3)} style={{ height: 40, width: 40, alignItems: 'center', justifyContent: 'center' }} >
            <LibIcon.SimpleLineIcons name='magnifier-add' />
          </Pressable>
          <View style={{ height: 40, width: 1, backgroundColor: '#060606', marginRight: 12 }} />
          {/* <Text style={{}} >{esp.lang("event/seat_map", "selected", String(data.filter((x) => x == -1).length), qty)}</Text> */}
          <LibTextstyle textStyle='callout'>{esp.lang("event/seat_map", "selected", String(getSelectedSeat().length), qty)}</LibTextstyle>
        </View>
        <EventButton
          backgroundColor={getSelectedSeat()?.length < qty ? "#999" : LibStyle.colorPrimary}
          testID={"save_btn"}
          style={{ margin: 7 }}
          label={esp.lang("event/seat_map", "save")}
          onPress={() => {
            let value = {
              seat_label: getSelectedSeat()
            }
            esp.log({ value });
            // return
            if (getSelectedSeat()?.length < qty) {
              LibToastProperty.show(esp.lang("event/seat_map", "seat_more", (qty - (getSelectedSeat()?.length)).toString()))
            } else {
              LibNavigation.sendBackResult(value, LibNavigation.getResultKey(props))
            }
          }}
        />
      </View>
    </View>
  )
}

function getLegends() {
  const colors: any = [
    ["#fff", esp.lang("event/seat_map", "available"), 0],
    // ["#8EF67B", esp.lang("event/seat_map", "chosen"), "-1"],
    ["#2EBBE8", esp.lang("event/seat_map", "reserved"), 3],
    // ["#6C432C", esp.lang("event/seat_map", "chosen_by"), 7],
    // ["#f1f2f3", esp.lang("event/seat_map", "way"), 5],
    // ["#9FA1A4", esp.lang("event/seat_map", "not_sold"), 1],
    ["#6B71E6", esp.lang("event/seat_map", "seat_hold"), 2],
    // ["#FF4866", esp.lang("event/seat_map", "wall"), 6],
    // ["#FFA601", esp.lang("event/seat_map", "other_type"), 4],
    // ["purple", esp.lang("event/seat_map", "stage"), 8]
    ["#7e2a0c", esp.lang("event/seat_map_new", "picked_byother"), 9]
  ]
  return colors
}

function getColorByStatus(statuses: number) {
  const colors: any = {
    0: '#fff',
    1: "#9FA1A4",
    2: "#6B71E6",
    3: "#2EBBE8",
    4: "#FFA601",
    5: "#fff",
    6: "#FF4866",
    7: "#6C432C",
    8: 'purple',
    9: "#7e2a0c"
  }
  return colors[statuses]
}