import bpy
import gpu
from bpy.props import FloatVectorProperty, CollectionProperty, IntProperty, BoolProperty
from bpy.types import Operator, PropertyGroup, UIList
from mathutils import Vector
from gpu_extras.batch import batch_for_shader
from . import operators
from . module import utils_base

# グローバルな描画データとハンドラーを保持する変数
draw_handle = None
draw_verts_data = []    # 描画する頂点データ
is_loop = False         # ループフラグ

# --------------------------------------------------------------------
# GPU描画関数 (修正版)
# --------------------------------------------------------------------
def draw_verts_polyline():
    """3Dビューポートにポリラインを描画する (選択状態と閉鎖に対応)"""
    global draw_verts_data, is_loop
    
    verts_list = draw_verts_data

    # ★ 描画リストが存在しない、または要素数が少ない場合は即座に終了
    if not verts_list or len(verts_list) < 2:
        return        

    try:
        # シェーダーを準備
        shader = gpu.shader.from_builtin('UNIFORM_COLOR')
    except Exception:
        return

    coords = [v.pont[:] for v in verts_list]
    num_verts = len(coords)
 
    print("ループフラグ", is_loop)
    # --------------------------
    # 1. 線分の描画
    # --------------------------
    
    # 線のインデックスと色を動的に設定
    line_indices = []
    line_colors = [] # 線分ごとに色を格納
    
    # 線分チェックのイテレーション回数
    # is_loop=Trueなら最後の線分 (N-1 -> 0) も含める
    iter_count = num_verts if is_loop else num_verts - 1
    
    for i in range(iter_count):
        idx1 = i
        idx2 = (i + 1) % num_verts # ループ対応
        
        v1_selected = verts_list[idx1].select
        v2_selected = verts_list[idx2].select
        
        # ★ 両端が選択されている場合に赤色 (R:1.0, G:1.0, B:0.0)
        if v1_selected and v2_selected:
            color = (1.0, 0.0, 0.0, 1.0) # 赤色
        else:
            color = (1.0, 1.0, 0.0, 1.0) # デフォルトの黄色
            
        line_indices.append((idx1, idx2))
        line_colors.extend([color, color]) # 線分の各頂点に色を割り当て
    
    if line_indices:
        gpu.state.line_width_set(2.0)
        batch_line = batch_for_shader(shader, 'LINES', {"pos": coords}, indices=line_indices)
        
        # 1.1 全線をデフォルト色 (黄) で描画
        shader.bind()
        shader.uniform_float("color", (1.0, 1.0, 0.0, 1.0)) 
        batch_line.draw(shader)

        # 1.2 両端が選択されている線を赤色で上書き描画
        mark_line_indices = []
        for i in range(iter_count):
             idx1 = i
             idx2 = (i + 1) % num_verts 
             if verts_list[idx1].select and verts_list[idx2].select:
                 mark_line_indices.append((idx1, idx2))
                 
        if mark_line_indices:
            batch_yellow_line = batch_for_shader(shader, 'LINES', {"pos": coords}, indices=mark_line_indices)
            shader.uniform_float("color", (1.0, 0.0, 0.0, 1.0)) # 赤色
            batch_yellow_line.draw(shader)

    # ----------------------------------------------------------------
    # 2. 点の描画 (選択された点と非選択の点で色分け)
    # ----------------------------------------------------------------
    selected_coords = [v.pont[:] for v in verts_list if v.select]
    unselected_coords = [v.pont[:] for v in verts_list if not v.select]

    gpu.state.point_size_set(7.0)
    
    # 2.1 選択された点を赤色で描画
    if selected_coords:
        batch_selected_point = batch_for_shader(shader, 'POINTS', {"pos": selected_coords})
        shader.uniform_float("color", (1.0, 0.0, 0.0, 1.0)) # 黄色
        batch_selected_point.draw(shader)

    # 2.2 非選択の点を黄色で描画
    if unselected_coords:
        batch_unselected_point = batch_for_shader(shader, 'POINTS', {"pos": unselected_coords})
        shader.uniform_float("color", (1.0, 1.0, 0.0, 1.0)) # 赤色
        batch_unselected_point.draw(shader)
    
    # 描画状態をリセット
    gpu.state.point_size_set(1.0)
    gpu.state.line_width_set(1.0)    

# --------------------------------------------------------------------
# select update 関数をクラス外で定義
# --------------------------------------------------------------------
def update_select(self, context):
    # Scene に保存されたオフセット値を使用
    if hasattr(context.scene, 'temp_offset'):
        offset = context.scene.temp_offset
        
        if self.select:
            self.pont[0] = self.base[0] + offset[0]
            self.pont[1] = self.base[1] + offset[1]
            self.pont[2] = self.base[2] + offset[2]
        else:
            self.pont[0] = self.base[0]
            self.pont[1] = self.base[1]
            self.pont[2] = self.base[2]
    if context.area and context.area.type == 'VIEW_3D':
        context.area.tag_redraw()

# --------------------------------------------------------------------
# offset update 関数をクラス外で定義
# --------------------------------------------------------------------
def update_offset(self, context):
    # オフセット値をシーンに一時保存
    context.scene.temp_offset = self.offset
    
    for v in self.verts:
        if v.select: 
            v.pont[0] = v.base[0] + self.offset[0]
            v.pont[1] = v.base[1] + self.offset[1]
            v.pont[2] = v.base[2] + self.offset[2]
        else:
            v.pont[0] = v.base[0]
            v.pont[1] = v.base[1]
            v.pont[2] = v.base[2]
    # ★ 描画ハンドラーが登録されていれば、3Dビューの再描画を強制
    if context.area and context.area.type == 'VIEW_3D':
        context.area.tag_redraw()
# --------------------------------------------------------------------
# ＵＩ用プロパティ
# --------------------------------------------------------------------
class VertexItem(PropertyGroup):
    pont: FloatVectorProperty(name="新座標", size=3, subtype='XYZ', default=(0.0, 0.0, 0.0))
    base: FloatVectorProperty(name="元座標", size=3, subtype='XYZ', default=(0.0, 0.0, 0.0))
    select: BoolProperty(
        name="Select", 
        default=False,
        update=update_select
    )

# --------------------------------------------------------------------
# ＵＩライン
# --------------------------------------------------------------------
class VERTS_UL_List(UIList):
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        row = layout.row(align=True)
        row.prop(item, "select", text="")
        row.label(text=f"{index:02d}: ({item.pont[0]:.3f}, {item.pont[1]:.3f}, {item.pont[2]:.3f})")

#---------------------------------------------------------------------
# セクション編集オペレーター
#---------------------------------------------------------------------
class ARCHI_OT_Edit_Section(Operator):
    bl_idname = "object.edit_section"
    bl_label = "Edit Section"
    bl_options = {'UNDO'}

    handle_name: bpy.props.StringProperty()
    prop_name: bpy.props.StringProperty()
    verts: CollectionProperty(type=VertexItem)
    index: IntProperty()
    # update 関数を紐付けた offset プロパティ
    offset: FloatVectorProperty(
        name="Offset",
        size=3,
        subtype='TRANSLATION',
        default=(0.0, 0.0, 0.0),
        update=update_offset
    )
    
    # --------------------------
    # invoke
    # --------------------------
    def invoke(self, context, event):
        global draw_handle, draw_verts_data, is_loop

        is_loop, verts_data = self.get_comp_section(context)
        self.verts.clear()
        for pont in verts_data:
            v = self.verts.add()
            v.pont = pont 
            v.base = pont
            # 初期選択状態は任意で設定
            v.select = False # 初期はすべて非選択
            
        # 描画データを初期化
        draw_verts_data = self.verts
        if not draw_handle:
             # 3Dビューに描画ハンドラーを登録
             draw_handle = bpy.types.SpaceView3D.draw_handler_add(
                 draw_verts_polyline, 
                 (), # draw_verts_polyline に渡す引数
                 'WINDOW', # 'WINDOW' または 'VIEW'
                 'POST_VIEW' # 3Dオブジェクトの後に描画
             )
        self.offset = (0.0,0.0,0.0)
        return context.window_manager.invoke_props_dialog(self, width=350)

    # --------------------------
    # draw
    # --------------------------
    def draw(self, context):
        layout = self.layout
        layout.template_list("VERTS_UL_List", "", self, "verts", self, "index")
        layout.prop(self, "offset")

    # --------------------------
    # execute
    # --------------------------
    def execute(self, context):
        for i, v in enumerate(self.verts):
            print(f"v{i}: {v.pont[:]}") 
        self.cancel(context) # 終了時にハンドラーを解除
        self.reset_section(context)
        return {'FINISHED'}

    # --------------------------
    # ハンドラー制御
    # --------------------------
    def modal(self, context, event):
        # ダイアログを閉じるイベントが発生した場合
        if event.type in {'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}
            
        # オフセットが変更されたときに、描画ハンドラーが常に最新のデータを参照するようにする
        # このオペレーター自体は invoke_props_dialog であり modalではないため、この部分は今回はスキップします。
        
        return {'PASS_THROUGH'}

    def cancel(self, context):
        """オペレーター終了時にハンドラーを解除する"""
        global draw_handle, draw_verts_data
        
        if draw_handle:
            # 描画ハンドラーを解除
            bpy.types.SpaceView3D.draw_handler_remove(draw_handle, 'WINDOW')
            draw_handle = None
            draw_verts_data = [] # データもクリア
            
        #return {'CANCELLED'}

    # --------------------------------------------------------------------
    # セクションデータ読出し
    # --------------------------------------------------------------------
    def get_comp_section(self, context):
        handle = context.active_object
        self.handle_name = handle.name      #ハンドルネーム
        self.prop_name = handle.prop_name   #プロパティネーム
        # ハンドル → シーンへコピー
        src_props = getattr(handle, self.prop_name)
        dst_props = getattr(context.scene, self.prop_name)
        utils_base.copy_props(src_props, dst_props, label=self.prop_name)
        dst_props.handle_name = self.handle_name
        flag = dst_props.close
        # リスト読み出し
        list = utils_base.verts_from_json(dst_props.path_json)
        print("座標リスト", list)
        return flag, list

    def reset_section(self, context):
        handle = bpy.data.objects.get(self.handle_name)
        props = getattr(context.scene, self.prop_name)
        points = []
        for v in self.verts:
            points.append(v.pont)
        props.path_json = utils_base.verts_to_json(points)
        # 再生成（最終確定）
        print("最終確定を実行します")
        # 確定: シーン → ハンドルへコピー
        handle_props = getattr(handle, self.prop_name)
        utils_base.copy_props(props, handle_props, label=self.prop_name)
        #再生成
        utils_base.clear_children(handle)
        operators.create_component(handle, context)
        #ハンドル選択
        bpy.ops.object.select_all(action='DESELECT')
        handle = bpy.data.objects.get(self.handle_name)
        context.view_layer.objects.active = handle
        handle.select_set(True)

#---------------------------------------------------------------------
#   クラスリスト
#---------------------------------------------------------------------
classes = (
    VertexItem, 
    VERTS_UL_List, 
    ARCHI_OT_Edit_Section
)

# --------------------------------------------------------------------
# 登録・解除
# --------------------------------------------------------------------
def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Scene.temp_offset = FloatVectorProperty(
        name="Temp Offset",
        size=3,
        default=(0.0, 0.0, 0.0)
    )


def unregister():
    del bpy.types.Scene.temp_offset
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)


#if __name__ == "__main__":
#    register()
#    bpy.ops.view3d.edit_verts_dialog('INVOKE_DEFAULT')