import * as cornerstoneTools from '@cornerstonejs/tools';
import * as cornerstone from "@cornerstonejs/core";
import dcmjs from '@/utils/dcmUpload/dcmjs'
import * as cornerstoneAdapters from "@cornerstonejs/adapters";
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
import * as polySeg from '@cornerstonejs/polymorphic-segmentation'
cornerstoneTools.init({ addons: { polySeg } })
import { getSegmentationList, getSegmentList } from '@/api/reading'
import Vue from 'vue'
const {
    ToolGroupManager,
    Enums: csToolsEnums,
    segmentation,
    annotation,
    LabelMapEditWithContourTool,
    SegmentBidirectionalTool,
    CrosshairsTool,
    utilities: CStUtils,
} = cornerstoneTools;
const { MouseBindings, Events: toolsEvents } = csToolsEnums
const { segmentation: segmentationUtils } = CStUtils;
const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone;
const { Cornerstone3D } = cornerstoneAdapters.adaptersSEG;
let viewportInfo = {}
let renderingEngineId = null
async function createSegmentation(toolGroupId, volumeId, segmentationId) {
    const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) || ToolGroupManager.getToolGroup('share-viewport-volume')
    toolGroup.setToolActive(
        LabelMapEditWithContourTool.toolName,
    );
    if (!cache.getVolume(segmentationId)) {
        await volumeLoader.createAndCacheDerivedLabelmapVolume(
            volumeId,
            {
                volumeId: segmentationId
            }
        )
    }
    if (!segmentation.state.getSegmentation(segmentationId)) {
        segmentation.addSegmentations([
            {
                segmentationId,
                representation: {
                    type: cornerstoneTools.Enums.SegmentationRepresentations
                        .Labelmap,
                    data: {
                        volumeId: segmentationId
                    }
                }
            }
        ]);
    }
}
async function createSegmentationRepresentation(viewportId, segmentationId) {
    segmentation.addSegmentationRepresentations(viewportId, [
        {
            segmentationId,
            type: csToolsEnums.SegmentationRepresentations.Labelmap,
        },
    ])
}
async function readSegmentation(obj, series, segmentationId, isFile = false) {
    let imageId = null
    if (isFile) {
        imageId = cornerstoneDICOMImageLoader.wadouri.fileManager.add(obj);
    } else {
        const imageIdObj = await cornerstoneDICOMImageLoader.wadouri.loadImage(`wadouri:${Vue.prototype.OSSclientConfig.basePath}${obj}`).promise
        imageId = imageIdObj.imageId
    }
    const image = await imageLoader.loadAndCacheImage(imageId);

    if (!image) {
        return;
    }

    const instance = metaData.get("instance", imageId);

    if (instance.Modality !== "SEG") {
        console.error("This is not segmentation: " + file.name);
        return;
    }

    const arrayBuffer = image.data.byteArray.buffer;
    await loadSegmentation(arrayBuffer, series, segmentationId);
}
async function loadSegmentation(arrayBuffer, series, segmentationId) {
    const generateToolState =
        await Cornerstone3D.Segmentation.generateToolState(
            series.ImageIds,
            arrayBuffer,
            metaData,
        );
    if (generateToolState.labelmapBufferArray.length !== 1) {
        alert(
            "Overlapping segments in your segmentation are not supported yet. You can turn on the skipOverlapping option but it will override the overlapping segments."
        );
        return;
    }
    // await createSegmentation(segmentationId);
    let arr = []
    generateToolState.segMetadata.data.forEach(item => {
        if (item) {
            let Target = JSON.parse(JSON.stringify(item))
            arr.push(Target)
        }
    })

    let mapping = {}

    arr.forEach((item, index) => {
        mapping[index + 1] = Number(item.SegmentNumber)
    })
    const megmentGroup =
        segmentation.state.getSegmentation(segmentationId);
    const { imageIds } = megmentGroup.representationData.Labelmap;
    const derivedSegmentationImages = imageIds.map(imageId =>
        cache.getImage(imageId)
    );

    const volumeScalarData = new Uint8Array(
        generateToolState.labelmapBufferArray[0]
    );
    const remappedData = new Uint8Array(volumeScalarData.length);
    for (let i = 0; i < volumeScalarData.length; i++) {
        const value = volumeScalarData[i];
        remappedData[i] = value === 0 ? 0 : (mapping[value] ? mapping[value] : value);
    }
    for (let i = 0; i < derivedSegmentationImages.length; i++) {
        const voxelManager = derivedSegmentationImages[i].voxelManager;
        const scalarData = voxelManager.getScalarData();
        scalarData.set(
            remappedData.slice(
                i * scalarData.length,
                (i + 1) * scalarData.length
            )
        );
        voxelManager.setScalarData(scalarData);
    }
}
function hex2Rgb(hexValue, alpha = 1) {
    const rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
    const hex = hexValue.replace(rgx, (m, r, g, b) => r + r + g + g + b + b);
    const rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    if (!rgb) {
        return hexValue;
    }
    const r = parseInt(rgb[1], 16),
        g = parseInt(rgb[2], 16),
        b = parseInt(rgb[3], 16);
    return [r, g, b, alpha * 255];
}
function removeSegmentFromViewport(viewportId) {
    return new Promise(resolve => {
        if (viewportInfo[viewportId] && viewportInfo[viewportId].length > 0) {
            viewportInfo[viewportId].forEach(async segmentationId => {
                segmentation.removeSegmentation(segmentationId)
                segmentation.state.removeSegmentation(segmentationId)
                let annotations = annotation.state.getAllAnnotations().filter(item => item.metadata.segmentationId && segmentationId === item.metadata.segmentationId && item.metadata.toolName === "SegmentBidirectional");
                annotations.forEach(item => {
                    annotation.state.removeAnnotation(item.annotationUID)
                })
            })
            resetViewport(viewportId)
        }
        viewportInfo[viewportId] = []
        resolve(true)
    })
}
function createSegmentConfiguration(segmentIndex, segmentationId, viewportId, actionConfiguration, otherSegments) {
    const containedSegmentIndices = otherSegments
        ? { has: (segmentIndex) => otherSegments.indexOf(segmentIndex) !== -1 }
        : undefined;
    const colorConfig = segmentation.config.color.getSegmentIndexColor(
        viewportId,
        segmentationId,
        segmentIndex
    );
    // Allow null style to skip style set
    let color, activeColor;
    if (colorConfig?.length) {
        color = `rgb(${colorConfig.join(',')})`;
        activeColor = color;
    }
    const style = {
        color,
        colorHighlightedActive: activeColor,
        colorActive: activeColor,
        textBoxColor: color,
        textBoxColorActive: activeColor,
        textBoxColorHighlightedActive: activeColor,
    };
    const label = otherSegments
        ? `Combined ${segmentIndex} with ${otherSegments.join(', ')}`
        : `Segment ${segmentIndex}`;

    actionConfiguration.contourBidirectional.data.segmentData.set(segmentIndex, {
        containedSegmentIndices,
        label,
        style,
    });
    actionConfiguration.contourBidirectional.data.segmentationId = segmentationId
    actionConfiguration.contourBidirectional.data.segmentIndex = segmentIndex
}
async function readingSegmentByConfig(series, visitInfo, viewportId, segmentationId, SegmentConfig) {
    let data = {
        SeriesId: series.Id,
        VisitTaskId: visitInfo.VisitTaskId,
        PageSize: 9999,
        PageIndex: 1,
    }
    let res = await getSegmentationList(data);
    if (res.IsSuccess) {
        let list = res.Result.CurrentPageData;
        changeInactiveSegmentShow(list, viewportId, segmentationId, SegmentConfig)
    }
    segmentation.config.style.setStyle(
        {
            type: csToolsEnums.SegmentationRepresentations.Labelmap,
        },
        {
            renderFill: SegmentConfig.renderFill,
            renderOutline: SegmentConfig.renderOutline,
            outlineWidth: Number(SegmentConfig.outlineWidth),
            fillAlpha: Number(SegmentConfig.fillAlpha),
        }
    )
}
function selectSegmentation(viewportId, segmentationId) {
    if (!segmentation.state.getSegmentation(segmentationId)) return false
    segmentation.activeSegmentation.setActiveSegmentation(viewportId, segmentationId)
}
function selectSegment(viewportId, segmentationId, segmentIndex) {
    if (!segmentIndex || !segmentationId) return false
    if (!segmentation.state.getSegmentation(segmentationId)) return false
    selectSegmentation(viewportId, segmentationId)
    segmentation.segmentIndex.setActiveSegmentIndex(segmentationId, segmentIndex);
}
async function changeInactiveSegmentShow(list, viewportId, segmentationId, SegmentConfig) {
    let segmentList = list
    segmentList.forEach(segment => {
        segmentation.config.visibility.setSegmentationRepresentationVisibility(
            viewportId,
            {
                segmentationId: segment.Id,
                type: csToolsEnums.SegmentationRepresentations.Labelmap,
            },
            SegmentConfig.InactiveSegmentations.show
        );
    })
    segmentation.config.visibility.setSegmentationRepresentationVisibility(
        viewportId,
        {
            segmentationId: segmentationId,
            type: csToolsEnums.SegmentationRepresentations.Labelmap,
        },
        true
    );
    let arr = []
    for (let i = 0; i < segmentList.length; i++) {
        let item = segmentList[i]
        let params = {
            SegmentationId: item.Id,
            PageSize: 9999,
            PageIndex: 1,
        }
        let r = await getSegmentList(params)
        if (r.IsSuccess) {
            let segments = r.Result.CurrentPageData
            segments.forEach(s => {
                let obj = {
                    segmentationId: item.Id,
                    segmentIndex: s.SegmentNumber,
                    view: SegmentConfig.InactiveSegmentations.show
                }
                if (item.Id === segmentationId) {
                    obj.view = true
                }
                arr.push(obj)
            })

        }
    }
    viewBidirectional(arr, viewportId)
}
function viewSegmentation(item, viewportId) {
    segmentation.config.visibility.setSegmentationRepresentationVisibility(
        viewportId,
        {
            segmentationId: item.segmentationId,
            type: csToolsEnums.SegmentationRepresentations.Labelmap,
        },
        item.view
    );
    viewBidirectional(item.segments, viewportId)
}
async function jumpBidirectional(item, viewportId, volumeId) {
    // DicomEvent.$emit('jumpBidirectional', item)
    if (item.bidirectional) {
        let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
        if (!an) return false
        if (['viewport-MPR-1', 'viewport-MPR-2'].includes(viewportId)) return false
        const renderingEngine = getRenderingEngine(renderingEngineId)
        const viewport = renderingEngine.getViewport(viewportId)
        let key = Object.keys(an.data.cachedStats)[0]; // referencedImageId
        if (key) {
            let sliceIndex = key.split("?")[1].split("&")[0].split("=")[1]
            csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIndex });
        } else {
            const points = an.data.handles.points;
            const worldPoint = points[0]; // 取一个点
            let volume = cache.getVolume(volumeId)
            let { imageData, numFrames } = volume
            const ijk = imageData.worldToIndex(worldPoint);
            const sliceIndex = Math.abs(Math.round(ijk[2]));
            // console.log(sliceIndex, 'sliceIndex')
            csUtils.jumpToSlice(viewport.element, { imageIndex: numFrames - sliceIndex - 1 });
        }

    }
}
function viewSegment(item, viewportId) {
    segmentation.config.visibility.setSegmentIndexVisibility(viewportId, {
        segmentationId: item.segmentationId,
        type: csToolsEnums.SegmentationRepresentations.Labelmap,
    }, item.segmentIndex, item.view)
    viewBidirectional([item], viewportId)
}
function viewBidirectional(arr, viewportId) {
    for (let j = 0; j < arr.length; j++) {
        let item = arr[j]
        let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
        // item.bidirectionalView = view
        if (!bidirectional) continue
        let view = item.view
        if (item.hasOwnProperty('bidirectionalView')) view = item.bidirectionalView
        annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, view)
    }
    resetViewport(viewportId)
}
function resetViewport(viewportId) {
    let renderingEngine = getRenderingEngine(renderingEngineId)
    const viewport = renderingEngine.getViewport(viewportId)
    viewport.render()
}
function changeColor(item, viewportId) {
    segmentation.config.color.setSegmentIndexColor(viewportId, item.segmentationId, item.segmentIndex, hex2Rgb(item.color))
}
async function renderSegmentation(series, visitInfo, viewportId, SegmentConfig, RenderingEngineId, Segment = null, actionConfiguration, segmentationId = null, segmentIndex = null) {
    try {
        // console.log(segmentation, 'segmentation')
        renderingEngineId = RenderingEngineId
        await removeSegmentFromViewport(viewportId)
        let data = {
            SeriesId: series.Id,
            VisitTaskId: visitInfo.VisitTaskId,
            PageSize: 9999,
            PageIndex: 1,
        }
        let res = await getSegmentationList(data);
        if (res.IsSuccess) {
            let list = res.Result.CurrentPageData;
            for (let i = 0; i < list.length; i++) {
                let item = list[i]
                if (!segmentationId) segmentationId = item.Id
                await createSegmentation(viewportId, series.SeriesInstanceUid, item.Id)
                if (item.SEGUrl) await readSegmentation(item.SEGUrl, series, item.Id)
                createSegmentationRepresentation(viewportId, item.Id)
                if (!viewportInfo[viewportId]) {
                    viewportInfo[viewportId] = [item.Id]
                } else {
                    viewportInfo[viewportId].push(item.Id)
                }
                let params = {
                    SegmentationId: item.Id,
                    PageSize: 9999,
                    PageIndex: 1,
                }
                let r = await getSegmentList(params)
                if (r.IsSuccess) {
                    let segments = r.Result.CurrentPageData
                    segments.forEach(s => {
                        if (!segmentIndex) segmentIndex = s.SegmentNumber
                        let SegmentJson = s.SegmentJson ? JSON.parse(s.SegmentJson) : {};
                        segmentation.segmentIndex.setActiveSegmentIndex(s.SegmentationId, s.SegmentNumber);
                        segmentation.config.color.setSegmentIndexColor(viewportId, s.SegmentationId, s.SegmentNumber, hex2Rgb(s.ColorRgb))
                        segmentation.segmentLocking.setSegmentIndexLocked(s.SegmentationId, s.SegmentNumber, s.IsLock)
                        if (SegmentJson.bidirectional) {
                            let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === s.SegmentationId && i.metadata.segmentIndex === SegmentJson.bidirectional.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
                            if (!an) {
                                let { majorAxis, minorAxis } = SegmentJson.bidirectional
                                // createSegmentConfiguration(s.SegmentNumber, s.SegmentationId, viewportId, actionConfiguration)
                                SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], {
                                    segmentIndex: s.SegmentNumber,
                                    segmentationId: s.SegmentationId,
                                })
                            }
                            an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === s.SegmentationId && i.metadata.segmentIndex === SegmentJson.bidirectional.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
                            if (an) {
                                annotation.locking.setAnnotationLocked(an.annotationUID, true)
                                annotation.visibility.setAnnotationVisibility(an.annotationUID, true)
                            }
                        }

                    })
                }
                if (segmentationId && segmentIndex) {
                    selectSegment(viewportId, segmentationId, segmentIndex)
                }

                if (Segment) {
                    jumpBidirectional(Segment, viewportId, series.SeriesInstanceUid)
                }
            }
        }
        readingSegmentByConfig(series, visitInfo, viewportId, segmentationId, SegmentConfig)
    } catch (err) {
        console.log(err)
    }
}

export {
    createSegmentation,
    createSegmentationRepresentation,
    readSegmentation,
    renderSegmentation,
    readingSegmentByConfig,
    selectSegment,
    selectSegmentation,
    viewSegmentation,
    viewSegment,
    jumpBidirectional,
    viewBidirectional,
    changeColor,
    resetViewport
}