
from typing import Optional, Tuple, Union

import flax
import flax.linen as nn
import jax
import jax.numpy as jnp
from flax.core.frozen_dict import FrozenDict

from ..configuration_utils import ConfigMixin, flax_register_to_config
from ..utils import BaseOutput
from .embeddings_flax import FlaxTimestepEmbedding, FlaxTimesteps
from .modeling_flax_utils import FlaxModelMixin
from .unet_ad_blocks_flax import (
    FlaxCrossAttnDownBlockaD,
    FlaxDownBlockaD,
    FlaxUNetMidBlockaDCrossAttn,
)


@flax.struct.dataclass
class     lowercase (		_SCREAMING_SNAKE_CASE       ):
		__lowercase	:	jnp.ndarray
		__lowercase	:	jnp.ndarray






class     lowercase (		nn.Module       ):
		__lowercase	:	int
		__lowercase	:	Tuple[int]     					=    (16, 32, 96, 256)
		__lowercase	:	jnp.dtype     					=    jnp.floataa



		def __UpperCamelCase			(			self	)  -> List[Any]:
				"""simple docstring"""
				UpperCamelCase          =					nn.Conv(
				    self.block_out_channels[0]    ,  kernel_size=(3, 3)    ,  padding=((1, 1), (1, 1))    ,  dtype=self.dtype    ,  )

				UpperCamelCase          =					[]
				for i in range(len(self.block_out_channels	) - 1	):
						UpperCamelCase          =					self.block_out_channels[i]
						UpperCamelCase          =					self.block_out_channels[i + 1]
						UpperCamelCase          =					nn.Conv(
						    A_    ,  kernel_size=(3, 3)    ,  padding=((1, 1), (1, 1))    ,  dtype=self.dtype    ,  )
						blocks.append(A_	)
						UpperCamelCase          =					nn.Conv(
						    A_    ,  kernel_size=(3, 3)    ,  strides=(2, 2)    ,  padding=((1, 1), (1, 1))    ,  dtype=self.dtype    ,  )
						blocks.append(A_	)
				UpperCamelCase          =					blocks

				UpperCamelCase          =					nn.Conv(
				    self.conditioning_embedding_channels    ,  kernel_size=(3, 3)    ,  padding=((1, 1), (1, 1))    ,  kernel_init=nn.initializers.zeros_init()    ,  bias_init=nn.initializers.zeros_init()    ,  dtype=self.dtype    ,  )



		def __call__(			self    ,  A_	)  -> List[Any]:
				"""simple docstring"""
				UpperCamelCase          =					self.conv_in(A_	)
				UpperCamelCase          =					nn.silu(A_	)

				for block in self.blocks:
						UpperCamelCase          =					block(A_	)
						UpperCamelCase          =					nn.silu(A_	)

				UpperCamelCase          =					self.conv_out(A_	)

				return embedding






@flax_register_to_config
class     lowercase (		nn.Module  ,       _SCREAMING_SNAKE_CASE  ,       _SCREAMING_SNAKE_CASE       ):
		__lowercase	:	int     					=    32
		__lowercase	:	int     					=    4
		__lowercase	:	Tuple[str]     					=    (
		    "CrossAttnDownBlock2D",
		    "CrossAttnDownBlock2D",
		    "CrossAttnDownBlock2D",
		    "DownBlock2D",
		)
		__lowercase	:	Union[bool, Tuple[bool]]     					=    False
		__lowercase	:	Tuple[int]     					=    (320, 640, 1_280, 1_280)
		__lowercase	:	int     					=    2
		__lowercase	:	Union[int, Tuple[int]]     					=    8
		__lowercase	:	Optional[Union[int, Tuple[int]]]     					=    None
		__lowercase	:	int     					=    1_280
		__lowercase	:	float     					=    0.0
		__lowercase	:	bool     					=    False
		__lowercase	:	jnp.dtype     					=    jnp.floataa
		__lowercase	:	bool     					=    True
		__lowercase	:	int     					=    0
		__lowercase	:	str     					=    "rgb"
		__lowercase	:	Tuple[int]     					=    (16, 32, 96, 256)



		def __UpperCamelCase			(			self    ,  A_	)  -> FrozenDict:
				"""simple docstring"""
				UpperCamelCase          =					(1, self.in_channels, self.sample_size, self.sample_size)
				UpperCamelCase          =					jnp.zeros(A_    ,  dtype=jnp.floataa	)
				UpperCamelCase          =					jnp.ones((1,)    ,  dtype=jnp.intaa	)
				UpperCamelCase          =					jnp.zeros((1, 1, self.cross_attention_dim)    ,  dtype=jnp.floataa	)
				UpperCamelCase          =					(1, 3, self.sample_size * 8, self.sample_size * 8)
				UpperCamelCase          =					jnp.zeros(A_    ,  dtype=jnp.floataa	)

				UpperCamelCase     ,  UpperCamelCase          =					jax.random.split(A_	)
				UpperCamelCase          =					{'params': params_rng, 'dropout': dropout_rng}

				return self.init(A_    ,  A_    ,  A_    ,  A_    ,  A_	)["params"]



		def __UpperCamelCase			(			self	)  -> Dict:
				"""simple docstring"""
				UpperCamelCase          =					self.block_out_channels
				UpperCamelCase          =					block_out_channels[0] * 4

				# If `num_attention_heads` is not defined (which is the case for most models)
				# it will default to `attention_head_dim`. This looks weird upon first reading it and it is.
				# The reason for this behavior is to correct for incorrectly named variables that were introduced
				# when this library was created. The incorrect naming was only discovered much later in https://github.com/huggingface/diffusers/issues/2011#issuecomment-1547958131
				# Changing `attention_head_dim` to `num_attention_heads` for 40,000+ configurations is too backwards breaking
				# which is why we correct for the naming here.
				UpperCamelCase          =					self.num_attention_heads or self.attention_head_dim

				# input
				UpperCamelCase          =					nn.Conv(
				    block_out_channels[0]    ,  kernel_size=(3, 3)    ,  strides=(1, 1)    ,  padding=((1, 1), (1, 1))    ,  dtype=self.dtype    ,  )

				# time
				UpperCamelCase          =					FlaxTimesteps(
				    block_out_channels[0]    ,  flip_sin_to_cos=self.flip_sin_to_cos    ,  freq_shift=self.config.freq_shift	)
				UpperCamelCase          =					FlaxTimestepEmbedding(A_    ,  dtype=self.dtype	)

				UpperCamelCase          =					FlaxControlNetConditioningEmbedding(
				    conditioning_embedding_channels=block_out_channels[0]    ,  block_out_channels=self.conditioning_embedding_out_channels    ,  )

				UpperCamelCase          =					self.only_cross_attention
				if isinstance(A_    ,  A_	):
						UpperCamelCase          =					(only_cross_attention,) * len(self.down_block_types	)

				if isinstance(A_    ,  A_	):
						UpperCamelCase          =					(num_attention_heads,) * len(self.down_block_types	)

				# down
				UpperCamelCase          =					[]
				UpperCamelCase          =					[]

				UpperCamelCase          =					block_out_channels[0]

				UpperCamelCase          =					nn.Conv(
				    A_    ,  kernel_size=(1, 1)    ,  padding='VALID'    ,  kernel_init=nn.initializers.zeros_init()    ,  bias_init=nn.initializers.zeros_init()    ,  dtype=self.dtype    ,  )
				controlnet_down_blocks.append(A_	)

				for i, down_block_type in enumerate(self.down_block_types	):
						UpperCamelCase          =					output_channel
						UpperCamelCase          =					block_out_channels[i]
						UpperCamelCase          =					i == len(A_	) - 1

						if down_block_type == "CrossAttnDownBlock2D":
								UpperCamelCase          =					FlaxCrossAttnDownBlockaD(
								    in_channels=A_    ,  out_channels=A_    ,  dropout=self.dropout    ,  num_layers=self.layers_per_block    ,  num_attention_heads=num_attention_heads[i]    ,  add_downsample=not is_final_block    ,  use_linear_projection=self.use_linear_projection    ,  only_cross_attention=only_cross_attention[i]    ,  dtype=self.dtype    ,  )
						else:
								UpperCamelCase          =					FlaxDownBlockaD(
								    in_channels=A_    ,  out_channels=A_    ,  dropout=self.dropout    ,  num_layers=self.layers_per_block    ,  add_downsample=not is_final_block    ,  dtype=self.dtype    ,  )

						down_blocks.append(A_	)

						for _ in range(self.layers_per_block	):
								UpperCamelCase          =					nn.Conv(
								    A_    ,  kernel_size=(1, 1)    ,  padding='VALID'    ,  kernel_init=nn.initializers.zeros_init()    ,  bias_init=nn.initializers.zeros_init()    ,  dtype=self.dtype    ,  )
								controlnet_down_blocks.append(A_	)

						if not is_final_block:
								UpperCamelCase          =					nn.Conv(
								    A_    ,  kernel_size=(1, 1)    ,  padding='VALID'    ,  kernel_init=nn.initializers.zeros_init()    ,  bias_init=nn.initializers.zeros_init()    ,  dtype=self.dtype    ,  )
								controlnet_down_blocks.append(A_	)

				UpperCamelCase          =					down_blocks
				UpperCamelCase          =					controlnet_down_blocks

				# mid
				UpperCamelCase          =					block_out_channels[-1]
				UpperCamelCase          =					FlaxUNetMidBlockaDCrossAttn(
				    in_channels=A_    ,  dropout=self.dropout    ,  num_attention_heads=num_attention_heads[-1]    ,  use_linear_projection=self.use_linear_projection    ,  dtype=self.dtype    ,  )

				UpperCamelCase          =					nn.Conv(
				    A_    ,  kernel_size=(1, 1)    ,  padding='VALID'    ,  kernel_init=nn.initializers.zeros_init()    ,  bias_init=nn.initializers.zeros_init()    ,  dtype=self.dtype    ,  )



		def __call__(			self    ,  A_    ,  A_    ,  A_    ,  A_    ,  A_ = 1.0    ,  A_ = True    ,  A_ = False    ,  )  -> Union[FlaxControlNetOutput, Tuple]:
				"""simple docstring"""
				UpperCamelCase          =					self.controlnet_conditioning_channel_order
				if channel_order == "bgr":
						UpperCamelCase          =					jnp.flip(A_    ,  axis=1	)

				# 1. time
				if not isinstance(A_    ,  jnp.ndarray	):
						UpperCamelCase          =					jnp.array([timesteps]    ,  dtype=jnp.intaa	)
				elif isinstance(A_    ,  jnp.ndarray	) and len(timesteps.shape	) == 0:
						UpperCamelCase          =					timesteps.astype(dtype=jnp.floataa	)
						UpperCamelCase          =					jnp.expand_dims(A_    ,  0	)

				UpperCamelCase          =					self.time_proj(A_	)
				UpperCamelCase          =					self.time_embedding(A_	)

				# 2. pre-process
				UpperCamelCase          =					jnp.transpose(A_    ,  (0, 2, 3, 1)	)
				UpperCamelCase          =					self.conv_in(A_	)

				UpperCamelCase          =					jnp.transpose(A_    ,  (0, 2, 3, 1)	)
				UpperCamelCase          =					self.controlnet_cond_embedding(A_	)
				sample += controlnet_cond

				# 3. down
				UpperCamelCase          =					(sample,)
				for down_block in self.down_blocks:
						if isinstance(A_    ,  A_	):
								UpperCamelCase     ,  UpperCamelCase          =					down_block(A_    ,  A_    ,  A_    ,  deterministic=not train	)
						else:
								UpperCamelCase     ,  UpperCamelCase          =					down_block(A_    ,  A_    ,  deterministic=not train	)
						down_block_res_samples += res_samples

				# 4. mid
				UpperCamelCase          =					self.mid_block(A_    ,  A_    ,  A_    ,  deterministic=not train	)

				# 5. contronet blocks
				UpperCamelCase          =					()
				for down_block_res_sample, controlnet_block in zip(A_    ,  self.controlnet_down_blocks	):
						UpperCamelCase          =					controlnet_block(A_	)
						controlnet_down_block_res_samples += (down_block_res_sample,)

				UpperCamelCase          =					controlnet_down_block_res_samples

				UpperCamelCase          =					self.controlnet_mid_block(A_	)

				# 6. scaling
				UpperCamelCase          =					[sample * conditioning_scale for sample in down_block_res_samples]
				mid_block_res_sample *= conditioning_scale

				if not return_dict:
						return (down_block_res_samples, mid_block_res_sample)

				return FlaxControlNetOutput(
				    down_block_res_samples=A_    ,  mid_block_res_sample=A_	)


from ...utils import (
    OptionalDependencyNotAvailable,
    is_torch_available,
    is_transformers_available,
    is_transformers_version,
)


try:
					if not (is_transformers_available() and is_torch_available() and is_transformers_version(">=", "4.25.0")):
										raise OptionalDependencyNotAvailable()
except OptionalDependencyNotAvailable:
					from ...utils.dummy_torch_and_transformers_objects import UnCLIPImageVariationPipeline, UnCLIPPipeline
else:
					from .pipeline_unclip import UnCLIPPipeline
					from .pipeline_unclip_image_variation import UnCLIPImageVariationPipeline
					from .text_proj import UnCLIPTextProjModel
