<template>
  <v-dialog
    v-model="isModal"
    persistent
    width="62.5rem"
  >  
    <div class="v-common-dialog-wrapper custom-dialog alert">
      <div class="modal-tit">
        <strong>장비 현황</strong>
        <button
          class="btn-close"
          @click="fnClose"
        />
      </div>
      
      <div class="v-common-dialog-content pa-0">
        <div class="core--list--component">
          <h2 class="fw--500">
            이벤트 현황
          </h2>
          <ul class="event--stat">
            <li class="critical">
              <i class="ico" /><span>CRITICAL</span><span>{{ neInfoItem.criCnt || 0 }}</span>
            </li>
            <li class="major">
              <i class="ico" /><span>MAJOR</span><span>{{ neInfoItem.majCnt || 0 }}</span>
            </li>
            <li class="minor">
              <i class="ico" /><span>MINOR</span><span>{{ neInfoItem.minCnt || 0 }}</span>
            </li>
            <li class="disconnected">
              <i class="ico" /><span>DISCONNECTED</span><span>0</span>
            </li>
          </ul>
        </div>

        <div class="core--list--component--grid mt--0">
          <div class="title">
            <h2>
              NE 그룹 목록 <span>({{ neGroupObj.count }}건)</span>
            </h2>
          </div>
          <div class="tbl-wrapper">
            <div class="tbl-wrap">
              <!-- ag grid -->
              <ag-grid-vue
                style="width:100%; height:calc(23vh);"
                class="ag-theme-quartz"
                :row-data="neGroupObj.list"
                :grid-options="neGroupGirdOptions"                                                                  
                @grid-ready="fnOnNeGroupGirdReady"
                @row-clicked="fnGroupRowClick" 
              />
            </div>
          </div>
        </div>

        <div class="core--list--component">
          <div class="map--area">
            <div
              v-if="neObj.neGroup"
              class="side--title"
              style="zIndex:10"
            >
              {{ neObj.neGroup }}
            </div>
            <!--맵 영역-->
            <div
              id="ran_detail_map"
              ref="refMap"
              style="height: 100%;"
            />
          </div>
        </div>
        
        <div class="core--list--component--grid mt--0">
          <div class="title">
            <h2 v-if="neObj.neGroup && neObj.count > 0">
              [{{ neObj.neGroup }}] NE 목록 <span>({{ neObj.count }}건)</span>
            </h2>
            <h2 v-else>
              NE 목록 <span>(0건)</span>
            </h2>
          </div>
          <div class="tbl-wrapper">
            <div class="tbl-wrap">
              <ag-grid-vue
                style="width:100%; height:22vh;"
                class="ag-theme-quartz"
                :grid-options="neGirdOptions"                                                                  
                @grid-ready="fnOnNeGirdReady"
              />
              <!-- :row-data="neObj.neList" -->
            </div>
          </div>
        </div>
      </div>

      <div
        class="btn-wrap nw--btn--wrap"
        style="padding-top:1.88rem"
      >
        <div />
        <div class="inner--btn--wrap">
          <v-btn
            class="custom-btn btn-gray mini"
            @click="fnClose"
          >
            <i class="ico" />
            닫기
          </v-btn>          
        </div>
      </div>
    </div>
  </v-dialog>  
</template>

<script setup>
  /***********************
   *     import
   ************************/
  import "ag-grid-community/styles/ag-grid.css";
  import "ag-grid-community/styles/ag-theme-quartz.css";
  import { AgGridVue } from "ag-grid-vue3";
  import { useI18n } from "vue-i18n";
  import useUtil from "@/composables/useUtil";
  import { filename } from 'pathe/utils'
  import testJson from "@/components/home/dashboard/test.json"


  /***********************
   *     plugins inject
   ************************/
   const { $toast, $log, $dayjs, $eventBus } = useNuxtApp()

  // props
  const props = defineProps({
    tenantName: {
      type: String, 
      required: true
    },
  })

  // 참조가능 데이터 설정
  defineExpose({})
  // 발신 이벤트 선언
  const emit = defineEmits(["closeModal"])
  const i18n = useI18n()

  /***********************
  *     data & created
  ************************/
  const isModal = ref(true)
  const refMap = ref();
  const map = ref(null)       // 카카오 맵 객체
  const markers = ref([])    // 카카오맵 마커(핀) 객체

  // 카카오맵 센터좌표
  const centerPosition = ref({
    lat: 33.450701,
    lng: 126.570667
  });

  const remToPx = () => parseFloat(getComputedStyle(document.documentElement).fontSize)
  const rowHeightRem = 2.5 // 원하는 rem 값
  const rowHeightPx = rowHeightRem * remToPx()
  const neGroupGridApi = shallowRef()
  const neGridApi = shallowRef()

  // Ran DetailInfo
  const neInfoItem = ref({});
  
  // neGroupObj
  const neGroupObj = ref({
    count: 0, 
    list: []
  });

  // neObj
  const neObj = ref({
    count: 0,
    neGroup: '', 
    list: []
  })

  

  // ne 그룹 목록 그리드 옵션
  const neGroupGirdOptions = {
    columnDefs: [
      { headerName: 'No', valueGetter: "node.rowIndex + 1", sortable: false, maxWidth: 100},    
      { headerName: 'NE 그룹명', field: 'neGroup', sortable: false, minWidth: 300}, 
      { headerName: 'NE 수', field: 'neCnt', sortable: false,},
      { headerName: '알림', field: 'cls', sortable: false,cellRenderer: alarmCellRenderer}
    ],
    rowData: neGroupObj.value.list,      // 테이블 데이터
    suppressMovableColumns: true,
    autoSizeStrategy: {
      type: "fitGridWidth", // width맞춤
    },  
    headerHeight : rowHeightPx,
    rowHeight: rowHeightPx,
    pagination: true,
    suppressPaginationPanel: true,    // 하단 default 페이징 컨트롤 숨김
    suppressRowClickSelection: true,  // 행 클릭 체크박스 무시
    localeText: {
      noRowsToShow: i18n.t('common.noData')
    },
  }

  // ne 목록 그리드 옵션
  const neGirdOptions = {
    defaultColDef: {
      lockVisible: true,
    },
    columnDefs: [
      { headerName: 'No', valueGetter: "node.rowIndex + 1", sortable: false,  maxWidth: 100},
      { headerName: 'NE 이름', field: 'neName', sortable: false, cellRenderer: neNameCellRenderer,},
      { headerName: '이벤트', field: 'eventStatus', sortable: false, cellRenderer: eventCellRenderer, width: 250,}
    ],
    rowData: neObj.value.neList,      // 테이블 데이터
    autoSizeStrategy: {
      type: "fitGridWidth", //fitCellContents
    },
    headerHeight : rowHeightPx,
    rowHeight: rowHeightPx,
    pagination: true,
    suppressPaginationPanel: true,    // 하단 default 페이징 컨트롤 숨김
    suppressRowClickSelection: true,  // 행 클릭 체크박스 무시
    localeText: {
      noRowsToShow: 'NE 그룹을 선택하세요'
    },
    loading: false    
  }




  /***********************
  *     Methods
  ************************/
  const fnInit = async () => {
    await nextTick();

    // Ran 정보 조회
    await fnGeoTenantNeInfo();

    // 카카오 지도 load
    if (window.kakao && window.kakao.maps) {
      fnLoadKakakoMap()
    } else {
      fnAppendKakaoScript()
    }
  }

  function fnClose(){
    isModal.value = false
    setTimeout(() => {
      emit('closeModal')
    }, 250);
  }

  /**
   * P5G RAN Ne 정보 조회
   */
   function fnGeoTenantNeInfo() {

    return new Promise((resolve, reject) => {
      const params = {
        tenantName: props.tenantName
      }

      useAxios().post(useApi.tenantNeInfo, params).then((res) => {

        const {resCode, resMsg, data} = res.data;

        if(resCode == 200) {
          // 테스트를 위한 테스트 코드 (삭제 필수)
          // fnParseData([...(data?.items || []), ...testJson.ranNeGroupList.data.items])

          fnParseData(data.items || [])

          $log.debug("[tenantDashboard][fnGeoTenantNeInfo][success]")
          resolve();
        } else {

          $log.debug("[tenantDashboard][fnGeoTenantNeInfo][error]", `[${resCode}] ${resMsg}`);
          reject()
        }
      }).catch((error)=>{

        // 테스트를 위한 테스트 코드 (삭제 필수)
        // fnParseData([...testJson.ranNeGroupList.data.items])

        $log.debug("[tenantDashboard][fnGeoTenantNeInfo][error]")
        useErrorHandler().fnSetCommErrorHandle(error, fnGeoTenantNeInfo)
        reject()
      }).finally(()=>{
        $log.debug("[tenantDashboard][fnGeoTenantNeInfo][finished]")
      })

    })
  }

  const fnParseData = (items = []) => {
    // main > criCnt, majCnt, minCnt, neCnt, neGroupCnt, neGroupList
    // neGroupList > criCnt, majCnt, minCnt, neCnt, neGroup, tenantName, neList
    // neList > 모든 데이터

    // "tenantName": "SAMSUNGSDS",
    // "neGroup": "tenant01Group01",
    // "neName": "tenant01Group01ne02",
    // "neId": "CPC_100",
    // "neType": "UPF",
    // "upfNum": 10,
    // "customerType": 1,
    // "lastUpdateTime": "2024-09-10 00:00:00",
    // "neAddress": "서울시",
    // "neLocLatitude": "37.55203063",
    // "neLocLongitude": "126.98081697",
    // "familyName": "PUD",
    // "initTime": "2024-09-01 18:15:00",
    // "minCnt": 0,
    // "majCnt": 0,
    // "criCnt": 0,
    // "kpi": "{\"UL_RX_AVG_KBPS\":\"0.00\",\"UL_TX_AVG_KBPS\":\"0.00\",\"DL_RX_AVG_KBPS\":\"0.00\",\"DL_TX_AVG_KBPS\":\"0.00\"}",
    // "cpu": "{\"AVG_CPU_L\":\"10\",\"PEAK_CPU_L\":\"11\"}",
    // "mem": "{\"AVG_MEM_L\":\"17\",\"PEAK_MEM_L\":\"17\"}",
    // "areaCode": 11

    neInfoItem.value = {};

    if(!items || items.length < 1) {
      return;
    }


    // 테넌트 필터링
    const tenantNeItems = items.filter((i) => i.tenantName == props.tenantName);
    // const tenantNeItems = items;

    // 데이터 그룹핑
    let objInfo = {};

    objInfo = tenantNeItems.reduce((acc, curr) => {
      // 심각도 카운트 셋팅
      if(acc.criCnt) acc.criCnt = acc.criCnt + curr.criCnt;
      else acc.criCnt = curr.criCnt;

      if(acc.majCnt) acc.majCnt = acc.majCnt + curr.majCnt;
      else acc.majCnt = curr.majCnt;

      if(acc.minCnt) acc.minCnt = acc.minCnt + curr.minCnt;
      else acc.minCnt = curr.minCnt;

      if(!acc.neGroupList) acc.neGroupList = [];

      // ne 카운트 셋팅
      if(acc.neCnt) acc.neCnt = acc.neCnt + 1;
      else acc.neCnt = 1;

      // neGroupList 셋팅
      const groupIndex = acc.neGroupList.findIndex((g) => g.neGroup == curr.neGroup);
      if(groupIndex > -1) {
        acc.neGroupList[groupIndex].neCnt = acc.neGroupList[groupIndex].neCnt + 1;
        acc.neGroupList[groupIndex].criCnt = acc.neGroupList[groupIndex].criCnt + curr.criCnt;
        acc.neGroupList[groupIndex].majCnt = acc.neGroupList[groupIndex].majCnt + curr.majCnt;
        acc.neGroupList[groupIndex].minCnt = acc.neGroupList[groupIndex].minCnt + curr.minCnt;
        acc.neGroupList[groupIndex].neList.push(curr);
      } else {
        acc.neGroupList.push({
          tenantName: curr.tenantName,
          neGroup: curr.neGroup,
          criCnt: curr.criCnt,
          majCnt: curr.majCnt,
          minCnt: curr.minCnt,
          neCnt: 1, 
          neList: [curr]
        })
      }

       //neGroup 카운트 셋팅
      if(acc.neGroupCnt) acc.neGroupCnt = acc.neGroupList?.length;
      else acc.neGroupCnt = 1; 

      return acc;
    }, {})

    // 전체 목록 셋팅
    neInfoItem.value = objInfo;

    // NE 그룹 목록 셋팅
    neGroupObj.value.count = objInfo.neGroupList?.length;
    neGroupObj.value.list = objInfo.neGroupList;

    console.log('::::: neGroup 정보 셋팅 완료 :::::', neInfoItem.value)
  }

  /**
   * 카카오 지도 관련
   */

  // 카카오 지도 script 추가
  const fnAppendKakaoScript = () => {
    const script = document.createElement('script')
    script.async = true
    script.onload = () => {
      window.kakao.maps.load(fnLoadKakakoMap)
    }
    script.src = `//dapi.kakao.com/v2/maps/sdk.js?autoload=false&libraries=services,clusterer,drawing&appkey=${import.meta.env.VITE_APP_KAKAO_APP_KEY}`
    document.head.appendChild(script)
  }

  // 카카오 지도 Load
  const fnLoadKakakoMap = () => {
    const mapContainer = refMap.value;
    const mapOption = {
      center: new kakao.maps.LatLng(centerPosition.value.lat, centerPosition.value.lng), // 지도의 중심좌표
      level: 12, // 지도의 확대 레벨
    }

    map.value = new kakao.maps.Map(mapContainer, mapOption)
  }

  /** 마커 관련 */
  // 마커 이미지 
  // 이미지 가져오기 (vite문법)
  const glob = import.meta.glob('~/assets/img/ico_*.{png,svg}', { eager: true })
  const getImages = Object.fromEntries(
    Object.entries(glob).map(([key, value]) => [filename(key), value.default])
  )
  const fnGetNePinIco = (item) => {
    const { criCnt, majCnt, minCnt } = item;
    if(criCnt && criCnt > 0) return 'red'
    else if(majCnt && majCnt > 0) return 'blue'
    else if(minCnt && minCnt > 0) return 'black'
    else return 'gray'
  }
  
  // 마커 생성
  const fnCreateMaker = (item, position, index) => {
    const markerImageSrc = getImages[`ico_${fnGetNePinIco(item)}_pin`];  // assets 폴더의 이미지 경로
    const markerImageSize = new kakao.maps.Size(40, 40); // 마커 이미지 사이즈
    const markerImage = new kakao.maps.MarkerImage(markerImageSrc, markerImageSize);
    const markerOption = {
      map: map.value,         // 마커를 표시할 지도
      position: position,     // 마커의 위치
      clickable: true,
      image: markerImage,
      zIndex: 1,
    }

    return new kakao.maps.Marker(markerOption);
  }

  // 마커 그리기
  const fnDrawMaker = () => {
    // 마커 초기화
    fnClearMarker();
    // 마커 생성
    neObj.value.neList.forEach((item, index) => {
      const position = new kakao.maps.LatLng(item.neLocLatitude, item.neLocLongitude)
      const marker = fnCreateMaker(item, position, index);
      markers.value.push({
        overlay: null,
        markers: marker,
        data: item,
        click: false,
        position: position
      })

      // 마커 클릭 이벤트등록
      kakao.maps.event.addListener(marker, 'click', fnClickMarkerEvent(index))

      // 첫번째 마커로 이동
      if(index == 0) map.value.panTo(position)
    })
  }

  // 마커 초기화
  const fnClearMarker = () => {
    markers.value.forEach(marker => marker.markers.setMap(null));
    fnClearMarkerOverlay()
    markers.value = []
  }

  // 마커 click 이벤트 등록
  function fnClickMarkerEvent(index) {
    const marker = markers.value[index];
    const openOverlay = () => {
      fnClickMaker(marker)
      fnOpenOverlay(marker)
    }

    return openOverlay;
  }

  // 실제 마커 클릭시 동작하는 함수
  const fnClickMaker = (marker) => {
    fnClearMakerClick();  // 마커 클릭 초기화
    marker.click = true;
    marker.markers.setZIndex(3)

    map.value.panTo(marker.position);
  }

  // 마커 Click 초기화
  const fnClearMakerClick = () => {
    markers.value.forEach((item) => {
      item.click = false;
      item.markers.setZIndex(2);
    })
  }

  /** 오버레이 윈도우 관련 */
  // 오버레이 open
  const fnOpenOverlay = (marker) => {
    // 모든 오버레이 초기화
    fnClearMarkerOverlay();
    // 오버레이 생성
    marker.overlay = fnCreateCustomOverlay(marker);
    // 오버레이 zindex 설정
    marker.overlay.setZIndex(999);
    // 오버레이 지도에 적용
    marker.overlay.setMap(map.value);

    // 오버레이 닫기 버튼
    const closeBtn = document.querySelector('#overlayCloseBtn')
    closeBtn.addEventListener('click', fnCloseOverlay)
  }

  // 오버레이 생성
  const fnCreateCustomOverlay = (marker) => {
    //kpi 정보 element 생성
    const kpiEls = (fnGetKPIInfo(marker?.data) || {}).map((kpi)=> {
      return `<li><i class="ico ${kpi.ico}"></i><span>${kpi.label}</span><span class="">${parseFloat(kpi.val|| 0).toFixed(2)}%</span></li>`
    });

    // custom overlay html 생성
    const contents = ` <div class="area--info" style="top: -10.7rem; right: -6rem;">
        <div class="area--info--title">
          <p style="overflow:hidden; text-overflow: ellipsis;">${marker?.data?.neName}</p>
          <button class="btn-close" id="overlayCloseBtn"></button>
        </div>
        <ul>
          <li><i class="ico green"></i><span>STATUS</span><span class="active">ACTIVE</span></li>
          ${kpiEls.join('')}
        </ul>
      </div>`;

    // overlay 생성
    return new kakao.maps.CustomOverlay({
      position: marker.position,
      content: contents
    })
  }

  // 오버레이에 표시할 KPI 정보 생성
  const fnGetKPIInfo = (data) => {
    // KPI 정보 셋팅 - TODO: CPU, MEM 외의 값이 추가되면 여기에 추가
    const { cpu, mem } = data;
    const kpiItems = [];

    const getBodyLevelClass = (val) => {
      if(val >= 95) return 'red';  // red
      else if(val >= 90) return 'blue';  // blue
      else if(val >= 85) return 'gray';  // gray
      else return 'green'; // green
    }

    if(cpu) {
      const objCpu = typeof cpu === 'string' ? JSON.parse(cpu) : cpu;
      if(objCpu && objCpu[`AVG_CPU_L`]){
        kpiItems.push({label: 'CPU', val: objCpu[`AVG_CPU_L`] || 0, ico: getBodyLevelClass(objCpu[`AVG_CPU_L`])})
      }

    }
    if(mem) {
      const objMem = typeof mem === 'string' ? JSON.parse(mem) : mem ; 
      if(objMem && objMem['AVG_MEM_L']){
        kpiItems.push({label: 'MEMORY', val: objMem['AVG_MEM_L'] || 0, ico: getBodyLevelClass(objMem[`AVG_MEM_L`])})
      }
    }

    return kpiItems;
  }

  // 오버레이 닫기 이벤트
  const fnCloseOverlay = () => {
    fnClearMarkerOverlay();
    fnClearMakerClick();
  }


  // 모든 마커 오버레이 초기화 
  const fnClearMarkerOverlay = () => {
    markers.value.forEach((marker) => {
      if(marker.overlay) {
        marker.overlay.setMap(null);
        marker.overlay = null;
      }
    })
  }


  /**
   * NE 그룹 목록 그리드 관련
   */
  function fnOnNeGroupGirdReady(params) {
    neGroupGridApi.value = params.api 
  }

  // 알림 Cell 렌더러
  function alarmCellRenderer(params) {
    let _cls = "";
    if(params.data.criCnt > 0){
      _cls = 'alarm--red';
    } else if(params.data.majCnt > 0){
      _cls = 'alarm--blue';
    } else if(params.data.minCnt > 0){
      _cls = 'alarm--gray'
    }
    return `<span class="${_cls}"></span>`;
  }
  
  //row clikc
  function fnGroupRowClick(params) {
    const { neList, neGroup } = params.data
    neObj.value.count = neList.length;
    neObj.value.neList = neList;
    // neObj.value.neList = neList.sort((a, b) => {
    //   return a.criCnt < b.criCnt ? 1 : a.criCnt > b.criCnt ? -1 : (a.majCnt < b.majCnt ? 1 : a.majCnt > b.majCnt ? -1 : (a.minCnt < b.minCnt ? 1 : a.minCnt > b.minCnt ? -1 : 0));
    // });
    neObj.value.neGroup = neGroup;
    // 그리드
    neGridApi.value.setGridOption('rowData', neObj.value.neList)

    // 지도에 마커 생성
    fnDrawMaker();
  }
  
  /**
   * NE 목록 그리드 관련
   */
  function fnOnNeGirdReady(params) {
    neGridApi.value = params.api 
  }

  // Ne 이름 Cell 렌더러
  function neNameCellRenderer(params) {
    let _cls = "";
    if(params.data.criCnt > 0){
      _cls = 'pin--red';
    } else if(params.data.majCnt > 0){
      _cls = 'pin--blue';
    } else if(params.data.minCnt > 0){
      _cls = 'pin--black'
    } else {
      _cls = 'pin--gray'
    }
    return `<span class="${_cls}">${params.data.neName}</span>`;
  }

  // 이벤트 Cell 렌더러
  function eventCellRenderer(params) {
    const { criCnt, majCnt, minCnt } = params.data;
    const events = [];
    if(criCnt && criCnt > 0) {
      events.push(`<span class="evt--critical">CRITICAL (${criCnt}) </span>`)
    }
    if(majCnt && majCnt > 0) {
      events.push(`<span class="evt--major">MAJOR (${majCnt}) </span>`)
    }
    if(minCnt && minCnt > 0) {
      events.push(`<span class="evt--minor">MINOR (${minCnt}) </span>`)
    }

    if(events.length > 0) {
      return events.join('');
    } else {
      return `<span class="evt--none">-</span>`;
    }

  }

  onMounted(() => fnInit())
</script>