package com.reason.lang.core.stub.type;

import com.intellij.lang.Language;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.stubs.*;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.io.StringRef;
import com.reason.Platform;
import com.reason.bs.BsConfigReader;
import com.reason.bs.BsPlatform;
import com.reason.ide.files.FileBase;
import com.reason.ide.search.index.IndexKeys;
import com.reason.lang.core.psi.PsiFakeModule;
import com.reason.lang.core.stub.PsiModuleStub;
import com.reason.lang.core.type.ORTypesUtil;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.Optional;

public class PsiFakeModuleStubElementType extends IStubElementType<PsiModuleStub, PsiFakeModule> {

    public PsiFakeModuleStubElementType(@NotNull String name, Language language) {
        super(name, language);
    }

    @NotNull
    public PsiFakeModule createPsi(@NotNull final PsiModuleStub stub) {
        return new PsiFakeModule(ORTypesUtil.getInstance(getLanguage()), stub, this);
    }

    @NotNull
    public PsiModuleStub createStub(@NotNull final PsiFakeModule fakeModule, final StubElement parentStub) {
        FileBase file = (FileBase) fakeModule.getContainingFile();

        // Finding if it's using a bs virtual namespace
        VirtualFile virtualFile = file.getViewProvider().getVirtualFile();
        VirtualFile originalFile = virtualFile instanceof LightVirtualFile ? ((LightVirtualFile) virtualFile).getOriginalFile() : virtualFile;
        String namespace = BsPlatform.findBsConfigForFile(file.getProject(), originalFile)
                .map((bsConfig) -> BsConfigReader.read(bsConfig).getNamespace())
                .orElse(null);

        return new PsiModuleStub(parentStub, this, file.getModuleName(), namespace /*, isVirtualNamespace*/, null, file.isComponent(), file.isInterface());
    }

    public void serialize(@NotNull final PsiModuleStub stub, @NotNull final StubOutputStream dataStream) throws IOException {
        dataStream.writeName(stub.getName());
        dataStream.writeUTFFast(stub.getQualifiedName());
        dataStream.writeBoolean(stub.isComponent());
        dataStream.writeBoolean(stub.isInterface());
    }

    @NotNull
    public PsiModuleStub deserialize(@NotNull final StubInputStream dataStream, final StubElement parentStub) throws IOException {
        StringRef moduleName = dataStream.readName();
        String qname = dataStream.readUTFFast();
        boolean isComponent = dataStream.readBoolean();
        boolean isInterface = dataStream.readBoolean();

        return new PsiModuleStub(parentStub, this, moduleName, qname, null, isComponent, isInterface);
    }

    public void indexStub(@NotNull final PsiModuleStub stub, @NotNull final IndexSink sink) {
        String name = stub.getName();
        if (name != null) {
            sink.occurrence(IndexKeys.MODULES, name);
        }

        sink.occurrence(IndexKeys.MODULES_TOP_LEVEL, name);

        String fqn = stub.getQualifiedName();
        sink.occurrence(IndexKeys.MODULES_FQN, fqn.hashCode());
        if (stub.isComponent()) {
            sink.occurrence(IndexKeys.MODULES_COMP, fqn);
        }
    }

    @NotNull
    public String getExternalId() {
        return getLanguage() + "." + super.toString();
    }
}

@@ -34,16 +34,76 @@
 .type;%0A%0A
+import java.io.*;%0Aimport org.jetbrains.annotations.NotNull;%0A
 import c
@@ -204,17 +204,211 @@
 i.stubs.
-*
+IStubElementType;%0Aimport com.intellij.psi.stubs.IndexSink;%0Aimport com.intellij.psi.stubs.StubElement;%0Aimport com.intellij.psi.stubs.StubInputStream;%0Aimport com.intellij.psi.stubs.StubOutputStream
 ;%0Aimport
@@ -496,36 +496,8 @@
 ef;%0A
-import com.reason.Platform;%0A
 impo
@@ -790,106 +790,8 @@
 til;
-%0Aimport org.jetbrains.annotations.NotNull;%0A%0Aimport java.io.IOException;%0Aimport java.util.Optional;
 %0A%0Apu
@@ -1677,16 +1677,62 @@
 espace =
+ originalFile == null ? null :%0A               
  BsPlatf
@@ -1787,33 +1787,16 @@
 nalFile)
-%0A                
 .map((bs
@@ -1851,33 +1851,16 @@
 space())
-%0A                
 .orElse(
@@ -3061,23 +3061,16 @@
 e);%0A    
-    %7D%0A%0A
         
@@ -3120,16 +3120,26 @@
 , name);
+%0A        %7D
 %0A%0A      

Fix a NPE