package net.ranides.demo.debugger.impl;

import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.ClassType;
import com.sun.jdi.TypeComponent;
import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.reflection.*;
import net.ranides.assira.reflection.impl.*;
import net.ranides.demo.debugger.DiClass;
import net.ranides.demo.debugger.DiException;
import net.ranides.demo.debugger.DiLocation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Optional;

public class CDiClass extends AClass<Object> implements DiClass {

    private final ClassType type;

    protected CDiClass(ClassType type) {
        this.type = type;
    }

    @Override
    public DiLocation locate(int line) {
        try {
            return new CDiLocation(type.locationsOfLine(line).get(0));
        } catch (AbsentInformationException ex) {
            throw new DiException(ex);
        }
    }

    @Override
    public List<IClass<?>> params() {
//        String gs = type.genericSignature();
        throw new UnsupportedOperationException("implement");
    }

    @Override
    public IFields fields() {
        AHints attr = FElements.newHints();
        return FElements.newFields(attr, CQuery.from().query(attr, this::getRFields));
    }

    private CQuery<IField> getRFields(AHints hints) {
        if(hints.hintDeclared()) {
            return CQuery.from()
                .collection(type.fields())
                .map(f -> new CDiField(true, f));
        } else if(hints.hintAny()) {
            return CQuery.from()
                .collection(type.allFields())
                .map(f -> new CDiField(isdecl(f), f));
        } else {
            return CQuery.from()
                .collection(type.visibleFields())
                .map(f -> new CDiField(isdecl(f), f));
        }
    }

    @Override
    public IConstructors<Object> constructors() {
//        type.methodsByName("<init>");
//        AHints attr = FElements.newHints();
//        return FElements.newConstructors(attr, Builder.fromQuery(attr, this::getRConstructors));
        throw new UnsupportedOperationException("implement");
    }

    @Override
    public IMethods methods() {
        AHints attr = FElements.newHints();
        return FElements.newMethods(attr, CQuery.from().query(attr, this::getRMethods));
    }

    private CQuery<IMethod> getRMethods(AHints hints) {
        if(hints.hintDeclared()) {
            return CQuery.from()
                .collection(type.methods())
                .map(m -> new CDiMethod(true, m));
        } else if(hints.hintAny()) {
            return CQuery.from()
                .collection(type.allMethods())
                .map(m -> new CDiMethod(isdecl(m), m));
        } else {
            return CQuery.from()
                .collection(type.visibleMethods())
                .map(m -> new CDiMethod(isdecl(m), m));
        }
    }

    private boolean isdecl(TypeComponent ref) {
        return type.equals(ref.declaringType());
    }

    @Override
    public IClass<?> parent() {
        return null;
    }

    @Override
    public IClasses parents() {
        return null;
    }

    @Override
    public IClasses interfaces() {
        return null;
    }

    @Override
    public IClass<?> outer() {
        return null;
    }

    @Override
    public IClasses inner() {
        return null;
    }

    @Override
    public Class<?> raw() {
        return null;
    }

    @Override
    public String shortName() {
        return null;
    }

    @Override
    public IClass<?> component() {
        return null;
    }

    @Override
    public Type reflective() {
        return null;
    }

    @Override
    public boolean isInstance(Object value) {
        return false;
    }

    @Override
    public Object cast(Object value) {
        return null;
    }

    @Override
    public IContext context() {
        return IContext.DEFAULT;
    }

    @Override
    public String name() {
        return type.name();
    }

    @Override
    public IAttributes attributes() {
        return null;
    }

    @Override
    public IAnnotations annotations() {
        return null;
    }

    @Override
    public <A extends Annotation> Optional<A> annotation(Class<A> type) {
        return Optional.empty();
    }
}
