from typing import List, Optional, Union, cast, TYPE_CHECKING
from .pseudo_pressures_results import PseudoPressuresResults
from .._private._tech_objects_api import TechObjectsAPI
from ..pvt_type_enum import PVTTypeEnum
from ..pvt_fluid_type_enum import PVTFluidTypeEnum
from .._private._tech_objects_dto import PVTQueryDto, BlackOilPvtQueryDto
from .black_oil_flash_results import BlackOilFlashResults
from .eos_flash_results import EosFlashResults
from .black_oil_pvt_property import BlackOilPvtProperty
from .rate_conversion_results import RateConversionResults
if TYPE_CHECKING:
    from .._private.dto_converters._pvt_dto_converter import PVTDtoConverter
[docs]
class PVT:
[docs]
    def __init__(self, field_id: str, well_id: Optional[str], id: str, name: str, technical_object_id: str, labels: Optional[List[str]], tech_objects_api: TechObjectsAPI, pvt_dto_converter: 'PVTDtoConverter') -> None:
        self.__field_id = field_id
        self.__well_id = well_id
        self.__id = id
        self.__name = name
        self.__technical_object_id = technical_object_id
        self.__labels = labels
        self.__tech_objects_api = tech_objects_api
        self.__pvt_dto_converter = pvt_dto_converter
        self.__pvt_dto: Optional[Union[BlackOilPvtQueryDto, PVTQueryDto]] = None 
    @property
    def field_id(self) -> str:
        """Gets the id of the field that contains this :class:`PVT`."""
        return self.__field_id
    @property
    def well_id(self) -> Optional[str]:
        """Gets the id of the well associated with this :class:`PVT`."""
        return self.__well_id
    @property
    def id(self) -> str:
        """Gets the unique id of this :class:`PVT`."""
        return self.__id
    @property
    def name(self) -> str:
        """Gets the name of this :class:`PVT`."""
        return self.__name
    @property
    def technical_object_id(self) -> str:
        """Gets the technical object id associated with this :class:`PVT`."""
        return self.__technical_object_id
    @property
    def labels(self) -> Optional[List[str]]:
        """Gets the labels associated with this :class:`PVT`."""
        return self.__labels
    @property
    def type(self) -> PVTTypeEnum:
        """Gets the type of this :class:`PVT`."""
        return self.__get_pvt_dto().pvtType
    def __get_pvt_dto(self) -> Union[BlackOilPvtQueryDto, PVTQueryDto]:
        if self.__pvt_dto is None:
            self.__pvt_dto = self.__tech_objects_api.get_pvt_properties(self.__technical_object_id)
        return self.__pvt_dto
    @property
    def properties(self) -> List[BlackOilPvtProperty]:
        if self.type is PVTTypeEnum.black_oil:
            return self.__pvt_dto_converter.build_pvt_properties(cast(BlackOilPvtQueryDto, self.__get_pvt_dto()).properties)
        else:
            raise ValueError("Properties are only available for black oil PVT types")
    @property
    def fluid_type(self) -> PVTFluidTypeEnum:
        if self.type is PVTTypeEnum.black_oil:
            return cast(BlackOilPvtQueryDto, self.__get_pvt_dto()).fluidType
        else:
            raise ValueError("Fluid type is only available for black oil PVT types")
    @property
    def reference_pressure(self) -> float:
        if self.type is PVTTypeEnum.black_oil:
            return cast(BlackOilPvtQueryDto, self.__get_pvt_dto()).parameters.referencePressure
        else:
            raise ValueError("Reference pressure is only available for black oil PVT types")
    @property
    def reference_temperature(self) -> float:
        if self.type is PVTTypeEnum.black_oil:
            return cast(BlackOilPvtQueryDto, self.__get_pvt_dto()).parameters.referenceTemperature
        else:
            raise ValueError("Reference temperature is only available for black oil PVT types")
[docs]
    def flash_black_oil_process(self, temperature: float, pressure: float, pb_imposed: bool, gor_or_pb: Optional[float] = None) -> BlackOilFlashResults:
        """Compute a flash on black oil PVT"""
        if self.type is PVTTypeEnum.black_oil:
            dto = self.__pvt_dto_converter.get_flash_black_oil_pvt_command_dto(temperature, pressure, pb_imposed, gor_or_pb)
            response = self.__tech_objects_api.flash_black_oil_pvt(self.__technical_object_id, dto)
            return self.__pvt_dto_converter.build_black_oil_flash_results(response)
        else:
            raise ValueError("This is not a black oil PVT") 
[docs]
    def flash_eos_process(self, temperature: float, pressure: float, extended: bool, water_molar_fraction: Optional[float] = None, salinity: Optional[float] = None) -> EosFlashResults:
        """Compute a flash on EoS PVT"""
        if self.type is PVTTypeEnum.eos:
            if (water_molar_fraction is None and salinity is None) or (water_molar_fraction is not None and salinity is not None):
                dto = self.__pvt_dto_converter.get_flash_eos_pvt_command_dto(temperature, pressure, extended, water_molar_fraction, salinity)
            else:
                raise ValueError("You must define water molar fraction and salinity")
            response = self.__tech_objects_api.flash_eos_pvt(self.__technical_object_id, dto)
            return self.__pvt_dto_converter.build_eos_flash_results(response)
        else:
            raise ValueError("This is not a EoS PVT") 
[docs]
    def compute_pseudo_pressures(self, temperature: float, rock_compressibility: float, pressure_range_min: float, pressure_range_max: float, pressure_range_steps: int, sw: Optional[float] = None) -> PseudoPressuresResults:
        dto = self.__pvt_dto_converter.get_compute_pseudo_pressures_command_dto(temperature, rock_compressibility, sw, pressure_range_min, pressure_range_max, pressure_range_steps=pressure_range_steps)
        pseudo_pressure_query_dto = self.__tech_objects_api.compute_pseudo_pressures(self.__technical_object_id, dto)
        return self.__pvt_dto_converter.build_pseudo_pressures_results(pseudo_pressure_query_dto) 
[docs]
    def convert_rates(self, field_pressures: List[List[float]], field_temperatures: List[List[float]], surface_pressures: List[List[float]], surface_temperatures: List[List[float]],
                      standard_oil_rates: List[float], standard_gas_rates: List[float]) -> RateConversionResults:
        dto = self.__pvt_dto_converter.get_rate_conversion_command_dto(field_pressures, field_temperatures, surface_pressures, surface_temperatures, standard_oil_rates, standard_gas_rates)
        rate_conversion_query_dto = self.__tech_objects_api.convert_rates(self.__technical_object_id, dto)
        return self.__pvt_dto_converter.build_rate_conversion_results(rate_conversion_query_dto)