/*
 * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package kotlin.reflect.jvm.internal

import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.typeUtil.builtIns
import kotlin.reflect.KType

internal fun createPlatformKType(lowerBound: KType, upperBound: KType): KType {
    // lowerBound/upperBound are guaranteed to be KTypeImpl over SimpleType, as long as this function is only used from the bytecode
    // generated by the compiler for `typeOf`.
    return KTypeImpl(
        KotlinTypeFactory.flexibleType(
            (lowerBound as KTypeImpl).type as SimpleType,
            (upperBound as KTypeImpl).type as SimpleType,
        )
    )
}

internal fun createMutableCollectionKType(type: KType): KType {
    val kotlinType = (type as KTypeImpl).type
    require(kotlinType is SimpleType) { "Non-simple type cannot be a mutable collection type: $type" }
    val classifier = kotlinType.constructor.declarationDescriptor as? ClassDescriptor
        ?: throw IllegalArgumentException("Non-class type cannot be a mutable collection type: $type")
    return KTypeImpl(
        KotlinTypeFactory.simpleType(kotlinType, constructor = classifier.readOnlyToMutable().typeConstructor)
    )
}

private fun ClassDescriptor.readOnlyToMutable(): ClassDescriptor {
    val fqName = JavaToKotlinClassMap.readOnlyToMutable(fqNameUnsafe)
        ?: throw IllegalArgumentException("Not a readonly collection: $this")
    return builtIns.getBuiltInClassByFqName(fqName)
}

internal fun createNothingType(type: KType): KType {
    val kotlinType = (type as KTypeImpl).type
    require(kotlinType is SimpleType) { "Non-simple type cannot be a Nothing type: $type" }
    return KTypeImpl(
        KotlinTypeFactory.simpleType(kotlinType, constructor = kotlinType.builtIns.nothing.typeConstructor)
    )
}
