// withHooks

import { EventButton } from 'esoftplay/cache/event/button/import';
import { EventHeader } from 'esoftplay/cache/event/header/import';
import { EventSeat_map_matrix } from 'esoftplay/cache/event/seat_map_matrix/import';
import { EventTap } from 'esoftplay/cache/event/tap/import';
import { LibCurl } from 'esoftplay/cache/lib/curl/import';
import { LibDialog } from 'esoftplay/cache/lib/dialog/import';
import { LibIcon } from 'esoftplay/cache/lib/icon/import';
import { LibLoading } from 'esoftplay/cache/lib/loading/import';
import { LibNavigation } from 'esoftplay/cache/lib/navigation/import';
import { LibObject } from 'esoftplay/cache/lib/object/import';
import { LibProgress } from 'esoftplay/cache/lib/progress/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 { LibUtils } from 'esoftplay/cache/lib/utils/import';
import { UseMap } from 'esoftplay/cache/use/map/import';
import esp from 'esoftplay/esp';
import useLazyState from 'esoftplay/lazy';
import { useTimeout } from 'esoftplay/timeout';
import React, { useEffect, useRef } from 'react';
import { Dimensions, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';


export type DataTicket = {
  "event_id": string,
  "event_title": string,
  "charge_payment": number,
  "charge_payment_type": string,
  "images": Array<{
    "image": string,
    "title": string,
    "description": string,
  }>,
  "qty": string,
  "selected_ticket": {
    "price_id": string,
    "type": string,
    "list": {
      "ondate": string,
    },
  },
}

export default function m(props: any) {
  const { dataTicket, url } = LibNavigation.getArgsAll<any>(props)
  const qty = dataTicket?.qty
  let numRows = useRef(0)
  let numCols = useRef(0)
  let selectedSeat = useRef<any>(null).current

  const [, setLockId, getLockId] = useLazyState(0)
  const [isLocks, setIsLocks, getIsLocks] = useLazyState({})
  const [, setIsSubmit, getIsSubmit] = useLazyState(false)
  const [, setLockedSeat, getLockedSeat] = useLazyState<any[]>([])
  const [seatNames, setSeatNames] = useLazyState<string[]>([])
  const [data, setData] = useLazyState<number[]>([])
  const [squareSize, setSquareSize] = useLazyState<number>(100)
  const [coordinates, setCoordinates] = useLazyState<string[]>([])
  const [selectedSeatData, setSelectedSeatData] = useLazyState<any>({})
  const [stage, setStage] = useLazyState('')
  const margin = squareSize * 0.25 // margin size in pixels
  const boxSize = squareSize + margin
  const timeout = useTimeout()
  const rB = squareSize * 0.1

  function next() {
    let x = squareSize * 3 / 2
    if (x <= 40) {
      LibProgress.show(esp.lang("event/seat_map", "zoom"))
      timeout(() => {
        setSquareSize(x)()
      }, 300)
    } else {
      LibToastProperty.show(esp.lang("event/seat_map", "zoom_max"))
    }
  }

  function prev() {
    let x = squareSize * 2 / 3
    if (x >= 10) {
      LibProgress.show(esp.lang("event/seat_map", "zoom_out"))
      timeout(() => {
        setSquareSize(x)()
      }, 300)
    } else {
      LibToastProperty.show(esp.lang("event/seat_map", "zoom_out_max"))
    }
  }

  useEffect(() => {
    timeout(() => {
      LibProgress.hide()
    }, 300)
  }, [squareSize])

  function resetZoom() {
    return setSquareSize((Dimensions.get('screen').width / numCols.current) * 0.8)
  }


  function lockRelease() {
    if (getLockedSeat().length > 0) {
      const y = getLockedSeat().map((item) => item.y).join('|')
      const x = getLockedSeat().map((item) => item.x).join('|')
      toggleLock(1, y, x, () => {
        loadData()
      })
    }
  }


  function toggleLock(lock: number, _y: string, _x: string, onDone?: () => void, onFailed?: (msg: string) => void) {
    const lockUrl = [
      'event_seat_lock_acquire',
      'event_seat_lock_release',
      'event_seat_lock_check'
    ]
    setLockId(getLockId() + 1)
    const idx = getLockId()

    setIsLocks(LibObject.set(getIsLocks(), false)(idx))
    new LibCurl(lockUrl[lock], {
      event_id: dataTicket.event_id,
      price_id: dataTicket?.selected_ticket?.price_id,
      ondate: dataTicket?.selected_ticket?.list?.ondate,
      row_id: _y,
      column_id: _x,
    },
      (res, msg) => {
        setIsLocks(LibObject.set(getIsLocks(), true)(idx))()
        onDone?.()
      },
      (err, msg) => {
        setIsLocks(LibObject.set(getIsLocks(), true)(idx))()
        onFailed?.(err.message)
      })
  }

  useEffect(() => {
    loadData()
    return () => {
      LibNavigation.cancelBackResult(LibNavigation.getResultKey(props))
      if (!getIsSubmit())
        lockRelease()
    }
  }, []);

  function loadData() {
    new LibCurl(url + '?' + LibUtils.objectToUrlParam({
      offset_row: 1, offset_column: 1
    }), {
      event_id: dataTicket.event_id,
      price_id: dataTicket?.selected_ticket?.price_id,
      ondate: dataTicket?.selected_ticket?.list?.ondate,
      compact: 4
    }, (res, msg) => {
      setStage(res.title)
      setLockedSeat(res.locked)
      lockRelease()
      numRows.current = res.seat_row
      numCols.current = res.seat_column
      resetZoom()
      setSeatNames(buildSeatNames(res.list.names, res.list.layout, setCoordinates))
      const sizes = res.list.statuses;
      const sizesArray: number[] = [];
      sizes?.split(",").forEach((size: string) => {
        if (size.includes('x')) {
          const [v, x] = size?.split("x");
          for (let i = 0; i < parseInt(v); i++) {
            sizesArray.push(parseInt(x));
          }
        } else {
          sizesArray.push(parseInt(size))
        }
      });
      setData(sizesArray)()
    }, (err) => {
      LibNavigation.back()
      LibToastProperty.show(err.message)
    }, 1)
  }

  function toggleSeat(x: number, y: number) {
    const cx = Math.floor(x / boxSize)
    const cy = Math.floor(y / boxSize)
    const index = (((cy * numCols.current) + cx))
    const [_x, _y] = coordinates[index]?.split?.(":")

    selectedSeat = {
      x: _x,
      y: _y,
      index: index,
      name: seatNames[index]
    }
    const countQty = data.filter((x) => x == -1).length
    setData(LibObject.update(data, (old) => {
      let out = old;
      if (old == 0) {
        if (countQty >= qty) {
          LibToastProperty.show(esp.lang("event/seat_map", "max_seat", qty))
        } else {
          setSelectedSeatData(LibObject.set(selectedSeatData, selectedSeat)(selectedSeat.index))
          out = -1;
          toggleLock(0, _y, _x)
        }
      }
      if (old == -1) {
        out = 0;
        setSelectedSeatData(LibObject.set(selectedSeatData, () => null)(selectedSeat.index))
        toggleLock(1, _y, _x)
      }
      return out
    })(selectedSeat.index))()
  }

  if (data.length == 0) {
    return <LibLoading />
  }

  const disabled = Object.values(isLocks).some((v) => v == false)

  return (
    <View style={styles.container}>
      <EventHeader title={esp.lang("event/seat_map", "header_title")} subtitle={dataTicket?.selected_ticket?.type} />
      <View style={{ alignItems: 'center', flex: 1 }}>
        <ScrollView showsVerticalScrollIndicator style={{ marginTop: 12 }} >
          <View style={{ marginVertical: 10 }} >
            <ScrollView 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>
          <View style={{ height: 40, marginLeft: 20, marginRight: 20, backgroundColor: LibStyle.colorPrimary, marginBottom: 20, borderRadius: 2, justifyContent: 'center', alignItems: 'center' }} >
            <Text style={{ color: 'white', fontWeight: 'bold' }} >{stage || esp.lang("event/seat_map", "front")}</Text>
          </View>
          <ScrollView horizontal showsHorizontalScrollIndicator >
            <EventTap onCoordinateGet={toggleSeat}>
              <EventSeat_map_matrix
                title={stage}
                data={data}
                mapWidth={numCols.current * boxSize + (margin)}
                mapHeight={numRows.current * boxSize + (margin)}
                seatNames={seatNames}
                numCols={numCols}
                boxSize={boxSize}
                margin={margin}
                squareSize={squareSize}
                rB={rB}
              />
            </EventTap>
          </ScrollView>
        </ScrollView>
      </View>
      <View style={{ flexDirection: 'row', marginHorizontal: 12, height: 40, borderColor: '#060606', borderWidth: 1, borderRadius: 5, alignItems: 'center' }} >
        <Pressable onPress={prev} style={{ height: 40, width: 40, alignItems: 'center', justifyContent: 'center' }} >
          <LibIcon.SimpleLineIcons name='magnifier-remove' />
        </Pressable>
        <Pressable onPress={next} 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>
      </View>
      <EventButton
        backgroundColor={disabled ? "#aaa" : LibStyle.colorPrimary}
        testID={"save_btn"}
        style={{ margin: 12 }}
        label={disabled ? esp.lang("event/seat_map", "wait") : esp.lang("event/seat_map", "save")}
        onPress={() => {
          if (disabled) {
            LibToastProperty.show(esp.lang("event/seat_map", "wait_toast"))
            return
          }
          const nonNull = Object.values(selectedSeatData).filter((x) => x != null)
          let value = {
            column_id: nonNull.map((x: any) => x.x).join('|'),
            row_id: nonNull.map((x: any) => x.y).join('|'),
            seat_name: nonNull.map((x: any) => x.name)
          }
          if (nonNull.length < qty) {
            LibToastProperty.show(esp.lang("event/seat_map", "seat_more", (qty - (nonNull.length)).toString()))
          } else {
            LibProgress.show(esp.lang("event/seat_map", "check_seat"))
            const nonNull = Object.values(selectedSeatData).filter((x) => x != null)
            toggleLock(2, nonNull.map((item: any) => item.y).join('|'), nonNull.map((item: any) => item.x).join('|'), () => {
              LibProgress.hide()
              setIsSubmit(true)
              LibNavigation.sendBackResult(value, LibNavigation.getResultKey(props))
            }, (msg) => {
              LibProgress.hide()
              LibDialog.warning(esp.lang("event/seat_map", "oops"), msg)
            })
          }
        }} />
    </View>
  );
}



function buildSeatNames(input: string, { letter_axis, letter_position }: any, cb?: (coordinates: string[]) => void) {
  const output = [];
  let coordinates = []
  const sections = input?.split?.(",");


  function renderNames(letter_axis: string, letter_position: number, x: number, y: number) {
    coordinates.push(x + ':' + y)
    if (letter_position == 0) {
      if (letter_axis == 'x')
        output.push(toBase26(x) + y)
      else if (letter_axis == 'y') {
        output.push(toBase26(y) + x)
      }
    } else {
      if (letter_axis == 'x')
        output.push(y + toBase26(x))
      else if (letter_axis == 'y') {
        output.push(x + toBase26(y))
      }
    }
  }


  for (let a = 0; a < sections.length; a++) {
    if (sections[a].length == 0) {
      output.push("")
      coordinates.push('0:0')
    } else {
      const [x, y] = sections[a]?.split?.(":")
      if (!x.includes("-") && !y.includes('-')) {
        renderNames(letter_axis, letter_position, parseInt(x), parseInt(y))
      } else {
        const [xfrom, xto] = x?.split("-")
        const [yfrom, yto] = y?.split("-")
        if (xto) {
          if (parseInt(xfrom) <= parseInt(xto)) {
            for (let i1 = parseInt(xfrom); i1 <= parseInt(xto); i1++) {
              renderNames(letter_axis, letter_position, i1, parseInt(y))
            }
          } else {
            coordinates.push('0:0')
            output.push("")
          }
        } else if (yto) {
          if (parseInt(yfrom) <= parseInt(yto)) {
            for (let i = parseInt(yfrom); i <= parseInt(yto); i++) {
              renderNames(letter_axis, letter_position, i, parseInt(y))
            }
          } else {
            coordinates.push('0:0')
            output.push("")
          }
        }
      }
    }
  }

  if (cb) cb(coordinates)

  return output
}


// Function to convert a number to base26
function toBase26(num: number) {
  let result = "";

  while (num > 0) {
    let remainder = (num - 1) % 26;
    result = String.fromCharCode(65 + remainder) + result;
    num = Math.floor((num - 1) / 26);
  }

  return result;
}

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]
  ]
  return colors
}


const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
});