import bpy
from bpy.props import StringProperty, IntProperty, FloatProperty, PointerProperty, EnumProperty, BoolProperty, CollectionProperty
from .utils import get_face_limit_max

class Hi3DTask(bpy.types.PropertyGroup):
    task_id: StringProperty(name="Task ID", default="")
    api_task_id: StringProperty(name="API Task ID", default="")
    task_type: StringProperty(name="Task Type", default="")
    create_time: StringProperty(name="Create Time", default="")
    image: PointerProperty(name="Input Image", type=bpy.types.Image)
    image_path: StringProperty(name="Image Path", default="")
    obj: PointerProperty(name="Target Object", type=bpy.types.Object)
    gen_status: EnumProperty(
        name="Generator Status",
        items=(
            ("INIT", "Initializing...", ""),
            ("QUEUE", "In Queue", ""),
            ("GEN_GEOM", "Generating Geometry...", ""),
            ("READY_TEX", "Ready for Texture", "✓ Clean floating meshes\n✓ Fix non-manifold geometry\n✓ Smooth major surfaces\n✓ Keep topology structure intact\n\nThen select the object and generate texture\nat Texture Generation."),
            ("FAIL", "Failed", ""),
        ),
        default="INIT",
    )
    tex_status: EnumProperty(
        name="Texture Status",
        items=(
            ("INIT", "Initializing...", ""),
            ("QUEUE", "In Queue", ""),
            ("GEN_TEX", "Generating Texture..", ""),
            ("DONE", "Done", ""),
            ("FAIL", "Failed", ""),
        ),
        default="INIT",
    )

class SelectedTask(bpy.types.PropertyGroup):
    index: IntProperty(name="Selected Index", default=0, min=0)
    type: StringProperty(name="Type", default="")

def _model_version_items(self, context):
    scene = None
    if context is not None and getattr(context, "scene", None) is not None:
        scene = context.scene
    else:
        try:
            import bpy
            scene = getattr(bpy.context, "scene", None)
        except Exception:
            scene = None
    model_type = getattr(scene, "hi3d_model_type", "GENERAL") if scene else "GENERAL"

    if model_type == "PORTRAIT":
        return [
            ("v2_1", "v2.1", ""),
            ("v2_0", "v2.0", ""),
            ("v1_5", "v1.5", ""),
        ]

    return [
        ("v2_1", "v2.1", ""),
        ("v2_0", "v2.0", ""),
        ("v1_5", "v1.5", ""),
    ]

def _resolution_items(self, context):
    # During registration, self might be None
    if self is None:
        return [
            ("1536fast", "1536 Fast", ""),
            ("1536pro", "1536 Pro", ""),
        ]
        
    scene = self
    
    if not hasattr(scene, "hi3d_model_version"):
        scene = getattr(context, "scene", None)
    
    if scene is None:
         return [
            ("1536fast", "1536 Fast", ""),
            ("1536pro", "1536 Pro", ""),
        ]

    ver = getattr(scene, "hi3d_model_version", "v1_5")
    model_type = getattr(scene, "hi3d_model_type", "GENERAL")

    if model_type == "GENERAL":
        if ver == "v2_1":
            return [
                ("1536fast", "1536 Fast", ""),
                ("1536pro", "1536 Pro", ""),
            ]
        if ver == "v2_0":
            return [
                ("1536pro", "1536 Pro", ""),
                ("1536", "1536", ""),
            ]
        return [
            ("512", "512", ""),
            ("1536", "1536", ""),
        ]

    if ver == "v2_1":
        return [
            ("1536fast", "1536 Fast", ""),
            ("1536pro", "1536 Pro", ""),
        ]
    if ver == "v2_0":
        return [
            ("1536pro", "1536 Pro", ""),
        ]
    return [
        ("1536", "1536", ""),
    ]

def _update_resolution(self, context):
    maxv = get_face_limit_max(self)
    self.hi3d_face_limit = maxv
    _update_generate_cost(self, context)

def _update_model_version(self, context):
    version_items = [i[0] for i in _model_version_items(self, context)]
    if getattr(self, "hi3d_model_version", None) not in version_items:
        self.hi3d_model_version = version_items[0]
    # Keep resolution valid for the new version/type
    items = [i[0] for i in _resolution_items(self, context)]
    
    if self.hi3d_resolution not in items:
        # Set to first valid item
        self.hi3d_resolution = items[0]
    _update_resolution(self, context)

def _update_model_type(self, context):
    # Same as version update
    _update_model_version(self, context)

def _update_face_limit(self, context):
    try:
        v = int(getattr(self, "hi3d_face_limit", 2000000))
    except Exception:
        v = 2000000
    v = max(100000, min(2000000, v))
    v = (v // 10000) * 10000
    if v != self.hi3d_face_limit:
        self.hi3d_face_limit = v

def _update_generate_cost(self, context):
    mt = getattr(self, "hi3d_model_type", "GENERAL")
    mv = getattr(self, "hi3d_model_version", "v2_0")
    res = getattr(self, "hi3d_resolution", "1536fast")
    mapping = {
        ("GENERAL", "v2_1", "1536fast"): 10,
        ("GENERAL", "v2_1", "1536pro"): 30,
        ("GENERAL", "v2_0", "1536"): 20,
        ("GENERAL", "v2_0", "1536pro"): 30,
        ("GENERAL", "v1_5", "512"): 5,
        ("GENERAL", "v1_5", "1536"): 20,
        ("PORTRAIT", "v2_1", "1536fast"): 10,
        ("PORTRAIT", "v2_1", "1536pro"): 30,
        ("PORTRAIT", "v2_0", "1536pro"): 30,
        ("PORTRAIT", "v1_5", "1536"): 20,
    }
    val = mapping.get((mt, mv, res), 30)
    if int(val) != getattr(self, "hi3d_generate_cost", 0):
        self.hi3d_generate_cost = int(val)


def register():
    bpy.utils.register_class(Hi3DTask)
    bpy.utils.register_class(SelectedTask)
    bpy.types.Scene.hi3d_url = StringProperty(
        name="URL",
        default="https://www.hitem3d.ai/",
    )
    bpy.types.Scene.hi3d_access_key = StringProperty(
        name="Access Key",
        default="",
    )
    bpy.types.Scene.hi3d_secret_key = StringProperty(
        name="Secret Key",
        default="",
        subtype="PASSWORD",
    )
    bpy.types.Scene.hi3d_authorization = StringProperty(
        name="Authorization",
        default="",
    )
    bpy.types.Scene.hi3d_balance = FloatProperty(
        name="User Balance",
        default=0.0,
        min=0.0,
    )
    bpy.types.Scene.hi3d_banner = PointerProperty(
        name="Banner",
        type=bpy.types.Image,
    )
    bpy.types.Scene.hi3d_model_type = EnumProperty(
        name="Model Type",
        items=(
            ("GENERAL", "General", ""),
            ("PORTRAIT", "Portrait", ""),
        ),
        default="GENERAL",
        update=_update_model_type,
    )
    bpy.types.Scene.hi3d_task_type = EnumProperty(
        name="Task",
        items=(
            ("IMAGE", "Image to 3D", ""),
            ("MULTI", "Multi-view to 3D", ""),
        ),
        default="IMAGE",
    )
    bpy.types.Scene.hi3d_model_version = EnumProperty(
        name="Model Version",
        items=_model_version_items,
        default=0,
        update=_update_model_version,
    )
    bpy.types.Scene.hi3d_resolution = EnumProperty(
        name="Resolution",
        items=_resolution_items,
        default=None,
        update=_update_resolution,
    )
    bpy.types.Scene.hi3d_face_limit = IntProperty(
        name="Face Limit",
        default=2000000,
        min=100000,
        max=2000000,
        update=_update_face_limit,
    )
    bpy.types.Scene.hi3d_input_image = PointerProperty(
        name="Input Image",
        type=bpy.types.Image,
    )
    bpy.types.Scene.hi3d_input_image_path = StringProperty(
        name="Input Image Path",
        default="",
    )
    bpy.types.Scene.hi3d_texture_image = PointerProperty(
        name="Texture Image",
        type=bpy.types.Image,
    )
    bpy.types.Scene.hi3d_texture_image_path = StringProperty(
        name="Texture Image Path",
        default="",
    )
    bpy.types.Scene.front_image = PointerProperty(
        name="Front Image",
        type=bpy.types.Image,
    )
    bpy.types.Scene.front_image_path = StringProperty(
        name="Front Image Path",
        default="",
    )
    bpy.types.Scene.right_image = PointerProperty(
        name="Right Image",
        type=bpy.types.Image,
    )
    bpy.types.Scene.right_image_path = StringProperty(
        name="Right Image Path",
        default="",
    )
    bpy.types.Scene.left_image = PointerProperty(
        name="Left Image",
        type=bpy.types.Image,
    )
    bpy.types.Scene.left_image_path = StringProperty(
        name="Left Image Path",
        default="",
    )
    bpy.types.Scene.back_image = PointerProperty(
        name="Back Image",
        type=bpy.types.Image,
    )
    bpy.types.Scene.back_image_path = StringProperty(
        name="Back Image Path",
        default="",
    )
    bpy.types.Scene.hi3d_generate_cost = IntProperty(
        name="Cost",
        default=10,
        min=0,
    )
    bpy.types.Scene.hi3d_texture_cost = IntProperty(
        name="Cost",
        default=10,
        min=0,
    )
    bpy.types.Scene.hi3d_confirmed = BoolProperty(
        name="Confirmed",
        default=False,
    )
    bpy.types.Scene.hi3d_tasks = CollectionProperty(type=Hi3DTask)
    bpy.types.Scene.hi3d_selected_task_index = IntProperty(name="Selected Task", default=0, min=0)
    bpy.types.Scene.hi3d_texture_tasks = CollectionProperty(type=Hi3DTask)
    bpy.types.Scene.hi3d_selected_texture_task_index = IntProperty(name="Selected Texture Task", default=0, min=0)
    bpy.types.Scene.hi3d_selected_texture_task = CollectionProperty(type=SelectedTask)
    bpy.types.Scene.hi3d_last_added_object_name = StringProperty(
        name="Selected Object",
        default="",
    )
    bpy.types.Scene.hi3d_selected_texture_task_id = StringProperty(
        name="Selected Texture Task ID",
        default="",
    )
    bpy.types.Scene.hi3d_selected_texture_task_type = StringProperty(
        name="Selected Texture Task Type",
        default="",
    )
    bpy.types.Scene.hi3d_selected_texture_task_create_time = StringProperty(
        name="Selected Texture Task Create Time",
        default="",
    )
    bpy.types.Scene.hi3d_is_generating = BoolProperty(
        name="Is Generating",
        default=False,
    )
    bpy.types.Scene.hi3d_is_generating_texture = BoolProperty(
        name="Is Generating Texture",
        default=False,
    )
    bpy.types.Scene.hi3d_is_replacing_texture = BoolProperty(
        name="Is Replacing Texture",
        default=False,
    )


def unregister():
    del bpy.types.Scene.hi3d_tasks
    del bpy.types.Scene.hi3d_selected_task_index
    del bpy.types.Scene.hi3d_texture_tasks
    del bpy.types.Scene.hi3d_selected_texture_task_index
    del bpy.types.Scene.hi3d_selected_texture_task
    del bpy.types.Scene.hi3d_texture_image
    bpy.utils.unregister_class(Hi3DTask)
    bpy.utils.unregister_class(SelectedTask)
    del bpy.types.Scene.hi3d_url
    del bpy.types.Scene.hi3d_access_key
    del bpy.types.Scene.hi3d_secret_key
    del bpy.types.Scene.hi3d_authorization
    del bpy.types.Scene.hi3d_balance
    del bpy.types.Scene.hi3d_banner
    del bpy.types.Scene.hi3d_model_type
    del bpy.types.Scene.hi3d_task_type
    del bpy.types.Scene.hi3d_model_version
    del bpy.types.Scene.hi3d_resolution
    del bpy.types.Scene.hi3d_face_limit
    del bpy.types.Scene.hi3d_input_image
    del bpy.types.Scene.hi3d_input_image_path
    del bpy.types.Scene.front_image
    del bpy.types.Scene.front_image_path
    del bpy.types.Scene.right_image
    del bpy.types.Scene.right_image_path
    del bpy.types.Scene.left_image
    del bpy.types.Scene.left_image_path
    del bpy.types.Scene.back_image
    del bpy.types.Scene.back_image_path
    del bpy.types.Scene.hi3d_generate_cost
    del bpy.types.Scene.hi3d_texture_cost
    del bpy.types.Scene.hi3d_confirmed
    del bpy.types.Scene.hi3d_last_added_object_name
    del bpy.types.Scene.hi3d_selected_texture_task_id
    del bpy.types.Scene.hi3d_selected_texture_task_type
    del bpy.types.Scene.hi3d_selected_texture_task_create_time
    del bpy.types.Scene.hi3d_is_generating
    del bpy.types.Scene.hi3d_is_generating_texture
    del bpy.types.Scene.hi3d_is_replacing_texture
