
import os
import re
import random
from pathlib import Path


from qgis.PyQt import uic, QtWidgets
from qgis.PyQt.QtWidgets import QApplication, QDialog, QMessageBox, QWidget


from qgis.core import QgsVectorLayer


import numpy as np
import pandas as pd
import geopandas as gpd
from shapely.geometry.base import BaseGeometry


import common
from urbanq.logging.logging_config import logger
from urbanq.function.qss import gradient_style, default_style


from urbanq.function.file import (
    export_gdf,
    keep_columns_gdf,
    load_geojson_gdf,
    load_txt_or_csv_df,
    load_json_df_or_gdf,
    load_layer_or_shp_gdf,
    update_shapefile_layer,
    df_to_empty_geometry_gdf,
)

from urbanq.function.geo import (
    is_real_null,
    is_empty_value,
    normalize_null_values,
)

from urbanq.function.widgetutils import (
    show_progress,
    update_progress,
)


from urbanq.menu.autoUI.fileRread_dockwidget import fileRreadDockWidget
from urbanq.menu.autoUI.fileSave_dockwidget import fileSaveDockWidget
from urbanq.menu.autoUI.fileSetting_dockwidget import fileSettingDockWidget
from urbanq.menu.autoUI.ImageDescription_dockwidget import ImageDescriptionDockWidget



FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'AttributeFieldManagement_dockwidget_base.ui'))


class AttributeFieldManagementDockWidget(QDialog, FORM_CLASS):  
    def __init__(self, parent=None):
        
        super(AttributeFieldManagementDockWidget, self).__init__(parent)  
        
        
        
        
        
        self.setupUi(self)

        
        show_progress(self.progressBar, False)

        
        self.menuPushButton.setProperty("class", "boldText")
        self.nextStepPushButton.setProperty("class", "boldText")
        self.previousStepPushButton.setProperty("class", "boldText")

        
        self.menuPushButton.clicked.connect(self.go_back_to_data_conversion)

        
        self.nextStepPushButton.clicked.connect(lambda: self.next_previous_clicked(1))
        self.nextStepPushButton.clicked.connect(lambda: self.update_current_progress(self.stackedWidget.currentIndex()))
        self.nextStepPushButton.clicked.connect(lambda: self.load_menu_ui(self.stackedWidget.currentIndex()))

        
        self.previousStepPushButton.clicked.connect(lambda: self.next_previous_clicked(-1))
        self.previousStepPushButton.clicked.connect(lambda: self.update_current_progress(self.stackedWidget.currentIndex()))
        self.previousStepPushButton.clicked.connect(lambda: self.load_menu_ui(self.stackedWidget.currentIndex()))

        
        self.job_index = common.job_info.get("job_index") if common.job_info else None
        self.job_title = common.job_info.get("job_title") if common.job_info else None

        
        self.option = self.get_widget_option(self.job_index, self.job_title)

        
        self.pages_and_files = self.configure_pages_and_files()

        
        self.update_current_progress(0)

        
        self.stackedWidget.setCurrentIndex(0)

        
        self.load_menu_ui(0)

    
    
    

    def configure_pages_and_files(self):
        
        try:
            pages = []

            
            pages.append((True, self.current_step_1, ImageDescriptionDockWidget, None, None))

            
            pages.append((True, self.current_step_2, fileRreadDockWidget, self.option, None))

            
            read_required = any([
                self.option["setting_by_text"],
                self.option["setting_by_array"],
                self.option["setting_by_expression"],
                self.option["setting_by_section"]["enabled"],
                self.option["setting_by_numeric"]["enabled"],
                self.option["setting_by_combo"]["enabled"],
            ])
            pages.append((read_required, self.current_step_3, fileSettingDockWidget, self.option, None))

            
            save_required = any([
                self.option["output_by_file"],
                self.option["output_by_field"],
                self.option["output_by_table"]
            ])
            pages.append((save_required, self.current_step_4, fileSaveDockWidget, self.option, None))

            return pages

        except Exception as e:
            logger.error("에러 발생: %s", e, exc_info=True)

    def go_back_to_data_conversion(self):
        
        try:
            from urbanq.menu.dataConversion.dataConversion_dockwidget import dataConversionDockWidget  
            parent_ui = dataConversionDockWidget(self)  
            main_page_layout = self.parent().parent().findChild(QWidget, "page_dataConversion").layout()
            if main_page_layout:
                
                for i in reversed(range(main_page_layout.count())):
                    main_page_layout.itemAt(i).widget().deleteLater()
                main_page_layout.addWidget(parent_ui)

        except Exception as e:
            logger.error("에러 발생: %s", e, exc_info=True)

    def load_menu_ui(self, index):
        
        try:
            widget_enabled, widget_process, widget_class, widget_option, widget_instance = self.pages_and_files[index]
            page = self.stackedWidget.widget(index)

            
            if widget_instance is None:

                
                widget_instance = widget_class(self, self.option)
                page.layout().addWidget(widget_instance)
                self.pages_and_files[index] = (
                    self.pages_and_files[index][0],
                    self.pages_and_files[index][1],
                    self.pages_and_files[index][2],
                    self.pages_and_files[index][3],
                    widget_instance
                )

        except Exception as e:
            logger.error("에러 발생: %s", e, exc_info=True)

    def update_current_progress(self, index):
        
        try:
            step = 1
            for i, (widget_enabled, widget_process, _, _, _) in enumerate(self.pages_and_files):
                if not widget_enabled:
                    widget_process.hide()
                    continue
                else:
                    updated_text = re.sub(r"\[\d+단계\]", f"[{step}단계]", widget_process.text())
                    widget_process.setText(updated_text)
                    step += 1

                
                widget_process.show()

                if i == index:
                    widget_process.setStyleSheet(gradient_style)
                else:
                    widget_process.setStyleSheet(default_style)

        except Exception as e:
            logger.error("에러 발생: %s", e, exc_info=True)

    def get_safe_page_index(self, current_index: int, direction: int) -> int:
        
        try:
            new_index = current_index

            while True:
                
                new_index += direction

                
                new_index = max(0, min(new_index, len(self.pages_and_files) - 1))

                
                if self.pages_and_files[new_index][0]:
                    return new_index

                
                if new_index == 0 and direction == -1:
                    return current_index

                
                if new_index == len(self.pages_and_files) - 1 and direction == 1:
                    return current_index

        except Exception as e:
            logger.error("에러 발생: %s", e, exc_info=True)

    def next_previous_clicked(self, direction):
        
        def get_last_valid_page_index(pages_and_files) -> int:
            
            for i in reversed(range(len(pages_and_files))):
                if pages_and_files[i][0]:
                    return i
            return -1  

        try:
            
            current_index = self.stackedWidget.currentIndex()

            
            if self.pages_and_files[current_index][0]:
                instance = self.pages_and_files[current_index][4]
                if direction > 0 and not instance.set_fileResults():
                    return

            
            new_index = self.get_safe_page_index(current_index, direction)

            
            last_page_index = get_last_valid_page_index(self.pages_and_files)

            
            self.nextStepPushButton.setText("실행하기 " if new_index == last_page_index else "다음 단계 ▶")

            
            self.stackedWidget.setCurrentIndex(new_index)

            
            if current_index == last_page_index and direction > 0:
                self.run_job_process()

        except Exception as e:
            logger.error("에러 발생: %s", e, exc_info=True)

    
    
    

    def get_file_data_frame(self, source_file_type, source_file_path, file_path, file_encoding, file_delimiter, file_has_header):
        
        try:
            
            gdf = None

            
            if source_file_type == "shp":
                gdf = load_layer_or_shp_gdf(shp_path=file_path, file_encoding=file_encoding)

            
            elif source_file_type == "layer":
                qgs_project_layer = source_file_path
                gdf = load_layer_or_shp_gdf(layer=qgs_project_layer, file_encoding=file_encoding)

            
            elif source_file_type == "json":
                df, _ = load_json_df_or_gdf(file_path=file_path, file_encoding=file_encoding)
                gdf = df_to_empty_geometry_gdf(df)

            
            elif source_file_type == "geojson":
                gdf = load_geojson_gdf(file_path=file_path, file_encoding=file_encoding)

            
            elif source_file_type == "txt":
                df = load_txt_or_csv_df(file_path, file_encoding, file_delimiter, file_has_header)
                gdf = df_to_empty_geometry_gdf(df)

            
            elif source_file_type == "csv":
                df = load_txt_or_csv_df(file_path, file_encoding, file_delimiter, file_has_header)
                gdf = df_to_empty_geometry_gdf(df)

            
            elif source_file_type == "folder":
                df = load_txt_or_csv_df(file_path, file_encoding, file_delimiter, file_has_header)
                gdf = df_to_empty_geometry_gdf(df)

            if gdf is None:
                return

            return gdf

        except Exception as e:
            logger.error("에러 발생: %s", e, exc_info=True)

    def run_job_process(self):
        
        try:
            
            show_progress(self.progressBar)

            
            total_files = len(common.fileInfo_1.file_preview)  
            steps_per_file = 4  
            total_steps = total_files * steps_per_file  
            base_progress = 20  
            step_weight = (100 - base_progress) / total_steps  
            current_step = 0  

            
            source_file_type, source_file_path, _ = common.fileInfo_1.file_record.get_record()
            result_file_type, result_file_path, _ = common.fileInfo_1.result_record.get_record()

            
            status_flags = []  
            for index, file_preview in enumerate(common.fileInfo_1.file_preview):

                
                file_path, file_encoding, file_delimiter, file_has_header = file_preview.get_info()
                current_step += 1
                update_progress(self.progressBar, int(base_progress + current_step * step_weight))

                
                if source_file_type == "folder":
                    
                    file_name_with_ext = os.path.basename(file_path)
                    new_file_path = os.path.join(result_file_path, file_name_with_ext)
                elif result_file_type == "layer":
                    new_file_path = file_path
                else:
                    new_file_path = result_file_path

                
                gdf = self.get_file_data_frame(source_file_type, source_file_path, file_path, file_encoding, file_delimiter, file_has_header)
                current_step += 1
                update_progress(self.progressBar, int(base_progress + current_step * step_weight))

                
                result = self.run_job_by_index(gdf, index)
                current_step += 1
                update_progress(self.progressBar, int(base_progress + current_step * step_weight))

                
                if result is None:
                    status_flags.append(False)
                    break
                elif result is True:
                    
                    
                    status_flags.append(True)

                try:
                    
                    if result_file_type == 'layer':

                        
                        layer_widget = self.pages_and_files[1][4].get_qgs_layer_widget()

                        
                        layer_widget_index = layer_widget.currentIndex()

                        
                        layer = source_file_path

                        
                        new_layer = update_shapefile_layer(layer, result)

                        
                        if 0 <= layer_widget_index < layer_widget.count():
                            layer_widget.setCurrentIndex(layer_widget_index)

                        
                        common.fileInfo_1.file_record.file_path[result_file_type] = new_layer

                        
                        status_flags.append(True)

                    else:
                        
                        if new_file_path:

                            
                            if isinstance(result, gpd.GeoDataFrame):
                                export_success = export_gdf(result, new_file_path)

                                
                                status_flags.append(export_success)

                            elif isinstance(result, list) and result:
                                
                                file_type, _, file_name = common.fileInfo_1.file_record.get_record()
                                base_dir = Path(new_file_path)
                                base_name = Path(file_name).stem
                                ext = f".{file_type}"

                                
                                export_success = []
                                for i, part in enumerate(result, start=1):
                                    output_path = base_dir / f"{base_name}_{i:03d}{ext}"
                                    export_success.append(export_gdf(part, output_path))

                                
                                status_flags.append(all(export_success))

                            else:
                                
                                QMessageBox.information(self, "파일 오류", "파일 저장 중 오류가 발생했습니다.", QMessageBox.Ok)
                                status_flags.append(False)

                except Exception as e:
                    
                    QMessageBox.information(self, "파일 오류", f"GeoDataFrame export 실패: {e}", QMessageBox.Ok)
                    status_flags.append(False)

                
                current_step += 1
                update_progress(self.progressBar, int(base_progress + current_step * step_weight))

            
            if status_flags and all(status_flags):
                update_progress(self.progressBar, 100)  
                QMessageBox.information(self, "알림", "축하합니다. 작업이 완료했습니다!", QMessageBox.Ok)

        except Exception as e:
            logger.error("에러 발생: %s", e, exc_info=True)

        finally:
            show_progress(self.progressBar, False)

    
    
    

    
    def generate_sequential_id_field(self, gdf, result_field="ID", start_from=0):
        
        try:
            
            gdf_copy = gdf.copy()

            
            gdf_copy[result_field] = range(start_from, start_from + len(gdf_copy))

            return gdf_copy

        except Exception as e:
            QMessageBox.information(self, "작업 오류", "고유 ID 필드 생성 중 오류가 발생하였습니다.", QMessageBox.Ok)
            logger.error("고유 ID 필드 생성 에러: %s", e, exc_info=True)
            return None

    
    def generate_random_digit_ids(self, gdf, digit_length=12, result_field="무작위ID"):
        
        try:
            
            if digit_length < 1 or digit_length > 18:
                QMessageBox.information(
                    self,
                    "입력 오류",
                    "자리수는 1자리 이상 18자리 이하만 허용됩니다.",
                    QMessageBox.Ok
                )
                return None

            
            gdf_copy = gdf.copy()
            n = len(gdf_copy)

            
            if len(str(n)) > digit_length:
                QMessageBox.information(
                    self,
                    "자리수 부족 가능성",
                    f"현재 레코드 수: {n:,}개 → {len(str(n))}자리\n"
                    f"입력한 숫자 자리수: {digit_length}자리\n\n"
                    "이 자리수로는 중복 없는 ID를 생성하기 어려울 수 있습니다.\n"
                    "더 큰 자리수를 입력해 주세요.",
                    QMessageBox.Ok
                )
                return None

            
            min_val = 10 ** (digit_length - 1)
            max_val = 10 ** digit_length - 1

            
            generated_set = set()
            random_ids = []
            while len(random_ids) < n:
                number = random.randint(min_val, max_val)
                if number not in generated_set:
                    generated_set.add(number)
                    random_ids.append(number)

            
            gdf_copy[result_field] = random_ids
            return gdf_copy

        except Exception as e:
            QMessageBox.information(
                self,
                "작업 오류",
                "무작위 숫자 생성 중 오류가 발생하였습니다.",
                QMessageBox.Ok
            )
            logger.error("무작위 ID 생성 에러: %s", e, exc_info=True)
            return None

    
    def add_empty_string_field(self, gdf, new_field_name, new_field_text):
        
        try:
            
            gdf_copy = gdf.copy()

            
            gdf_copy[new_field_name] = new_field_text

            return gdf_copy

        except Exception as e:
            QMessageBox.information(self, "작업 오류", "새 문자열 필드 생성 중 오류가 발생하였습니다.", QMessageBox.Ok)
            logger.error("새 문자열 필드 생성 에러: %s", e, exc_info=True)
            return None

    
    def rename_field(self, gdf, old_field_name, new_field_name):
        
        try:
            
            gdf_copy = gdf.copy()

            
            if old_field_name not in gdf_copy.columns:
                QMessageBox.information(self, "입력 오류", f"기존 필드명 '{old_field_name}'이 존재하지 않습니다.", QMessageBox.Ok)
                return None

            
            if new_field_name in gdf_copy.columns:
                QMessageBox.information(self, "입력 오류", f"새 필드명 '{new_field_name}'이 이미 존재합니다.", QMessageBox.Ok)
                return None

            
            if (
                    not re.match(r'^[A-Za-z가-힣_][A-Za-z0-9가-힣_]*$', new_field_name)
                    or len(new_field_name.encode("utf-8")) > 10
            ):
                QMessageBox.warning(
                    self,
                    "필드명 오류",
                    "필드명은 영문/한글 또는 밑줄(_)로 시작해야 하며,\n"
                    "영문자, 한글, 숫자, 밑줄(_)만 사용할 수 있습니다.\n"
                    "또한 Shapefile 규격상 필드명은 UTF-8 기준 10바이트 이내여야 합니다.\n\n"
                    "예) 한글 3글자 + 영문 1글자 = 10바이트"
                )
                return False

            
            gdf_copy.rename(columns={old_field_name: new_field_name}, inplace=True)

            return gdf_copy

        except Exception as e:
            QMessageBox.information(self, "작업 오류", "필드 이름 변경 중 오류가 발생하였습니다.", QMessageBox.Ok)
            logger.error("필드 이름 변경 에러: %s", e, exc_info=True)
            return None

    
    def convert_field_to_numeric_auto(self, gdf, target_field, result_field=None):
        

        def convert_numeric_fill_zero(series):
            
            numeric = pd.to_numeric(series, errors="coerce").fillna(0)

            if (numeric % 1 == 0).all():
                return numeric.astype("Int64"), "정수형(int)"
            else:
                return numeric.astype(float), "실수형(float)"

        try:
            gdf_copy = gdf.copy()

            
            numeric_series, used_type = convert_numeric_fill_zero(gdf_copy[target_field])

            if numeric_series is None:
                QMessageBox.information(
                    self,
                    "변환 실패",
                    "선택한 필드를 숫자 형식(int 또는 float)으로 변환할 수 없습니다.",
                    QMessageBox.Ok
                )
                return None

            
            if result_field and result_field != target_field:
                gdf_copy[result_field] = numeric_series
            else:
                gdf_copy[target_field] = numeric_series

            return gdf_copy

        except Exception as e:
            QMessageBox.information(self, "작업 오류", "숫자 변환 중 오류가 발생하였습니다.", QMessageBox.Ok)
            logger.error("숫자 변환 오류: %s", e, exc_info=True)
            return None

    
    def reorder_fields(self, gdf, new_field_order):
        
        try:
            
            geometry_col = gdf.geometry.name

            
            valid_fields = [field for field in new_field_order if field in gdf.columns]

            
            reordered_gdf = gdf[valid_fields + [geometry_col]].copy()

            return reordered_gdf

        except Exception as e:
            QMessageBox.information(None, "작업 오류", "필드 순서 변경 중 오류가 발생하였습니다.", QMessageBox.Ok)
            logger.error("필드 순서 변경 오류: %s", e, exc_info=True)
            return None

    
    def copy_field_values(self, gdf, source_field, new_field_name):
        
        try:
            
            gdf_copy = gdf.copy()
            gdf_copy[new_field_name] = gdf_copy[source_field]

            return gdf_copy

        except Exception as e:
            QMessageBox.information(self, "작업 오류", "필드 복사 중 오류가 발생하였습니다.", QMessageBox.Ok)
            logger.error("필드 복사 오류: %s", e, exc_info=True)
            return None

    
    
    

    @staticmethod
    def get_widget_option(job_index, job_title):
        
        try:
            option = None  
            job_title = job_title[2:]

            if job_index == 0:
                option = {
                    "apply_basic_qss": True,

                    "disable_file_type_layer": True,
                    "disable_file_type_shp": True,
                    "disable_file_type_json": True,
                    "disable_file_type_txtcsv": True,
                    "disable_file_type_fold": False,

                    "show_uid_in_file": False,
                    "show_tuid_in_file": False,
                    "show_field_in_file": False,

                    "setting_by_text": False,
                    "setting_by_array": False,
                    "setting_by_expression": False,
                    "setting_by_section": {"enabled": False, "value_type": "int"},
                    "setting_by_numeric": {"enabled": False, "value_type": "int"},
                    "setting_by_combo": {"enabled": False, "items": []},

                    "output_by_file": True,
                    "output_by_field": True,
                    "output_by_table": False,

                    "RESULT_FIELD": [
                        '고유 ID 저장 필드 생성',
                        '필드명 입력: ',
                        ''
                    ],
                }
            if job_index == 1:
                option = {
                    "apply_basic_qss": True,

                    "disable_file_type_layer": True,
                    "disable_file_type_shp": True,
                    "disable_file_type_json": True,
                    "disable_file_type_txtcsv": True,
                    "disable_file_type_fold": False,

                    "show_uid_in_file": False,
                    "show_tuid_in_file": False,
                    "show_field_in_file": False,

                    "setting_by_text": True,
                    "setting_by_array": False,
                    "setting_by_expression": False,
                    "setting_by_section": {"enabled": False, "value_type": "int"},
                    "setting_by_numeric": {"enabled": False, "value_type": "int"},
                    "setting_by_combo": {"enabled": False, "items": []},

                    "output_by_file": True,
                    "output_by_field": True,
                    "output_by_table": False,

                    "SETTING_TEXT": [
                        '무작위 N자리 숫자 설정',
                        '자리 수 입력: ',
                        '생성할 무작위 숫자의 자리 수를 입력해 주세요 (예: 6, 12 등).'
                    ],

                    "RESULT_FIELD": [
                        '무작위 숫자 저장 필드 생성',
                        '필드명 입력: ',
                        ''
                    ],
                }
            if job_index == 2:
                option = {
                    "apply_basic_qss": True,

                    "disable_file_type_layer": True,
                    "disable_file_type_shp": True,
                    "disable_file_type_json": True,
                    "disable_file_type_txtcsv": True,
                    "disable_file_type_fold": False,

                    "show_uid_in_file": False,
                    "show_tuid_in_file": False,
                    "show_field_in_file": False,

                    "setting_by_text": True,
                    "setting_by_array": False,
                    "setting_by_expression": False,
                    "setting_by_section": {"enabled": False, "value_type": "int"},
                    "setting_by_numeric": {"enabled": False, "value_type": "int"},
                    "setting_by_combo": {"enabled": False, "items": []},

                    "output_by_file": True,
                    "output_by_field": True,
                    "output_by_table": False,

                    "SETTING_TEXT": [
                        '문자열 초기값 설정',
                        '초기값 입력: ',
                        '새로 생성되는 문자열 필드에 적용할 초기값을 입력해 주세요 (예: 미입력).'
                    ],

                    "RESULT_FIELD": [
                        '새로운 문자열 필드 추가',
                        '필드명 입력: ',
                        ''
                    ],
                }

            if job_index == 3:
                option = {
                    "apply_basic_qss": True,

                    "disable_file_type_layer": True,
                    "disable_file_type_shp": True,
                    "disable_file_type_json": True,
                    "disable_file_type_txtcsv": True,
                    "disable_file_type_fold": False,

                    "show_uid_in_file": False,
                    "show_tuid_in_file": True,
                    "show_field_in_file": False,

                    "setting_by_text": True,
                    "setting_by_array": False,
                    "setting_by_expression": False,
                    "setting_by_section": {"enabled": False, "value_type": "int"},
                    "setting_by_numeric": {"enabled": False, "value_type": "int"},
                    "setting_by_combo": {"enabled": False, "items": []},

                    "output_by_file": True,
                    "output_by_field": False,
                    "output_by_table": False,

                    "FILE_TUID": [
                        '이름을 변경할 필드 선택',
                        '필드 선택: ',
                        '이름을 변경할 대상 필드를 선택해 주세요.'
                    ],

                    "SETTING_TEXT": [
                        '새 필드명 입력',
                        '필드명 입력: ',
                        '이전 단계에서 선택한 필드의 이름을 새 필드명으로 변경합니다.'
                    ],
                }
            if job_index == 4:
                option = {
                    "apply_basic_qss": True,

                    "disable_file_type_layer": True,
                    "disable_file_type_shp": True,
                    "disable_file_type_json": True,
                    "disable_file_type_txtcsv": True,
                    "disable_file_type_fold": False,

                    "show_uid_in_file": False,
                    "show_tuid_in_file": True,
                    "show_field_in_file": False,

                    "setting_by_text": False,
                    "setting_by_array": False,
                    "setting_by_expression": False,
                    "setting_by_section": {"enabled": False, "value_type": "int"},
                    "setting_by_numeric": {"enabled": False, "value_type": "int"},
                    "setting_by_combo": {"enabled": False, "items": []},

                    "output_by_file": True,
                    "output_by_field": True,
                    "output_by_table": False,

                    "FILE_TUID": [
                        '숫자 유형으로 변환할 필드 선택',
                        '필드 선택: ',
                        '숫자 유형으로 변환할 대상 필드를 선택해 주세요.'
                    ],

                    "RESULT_FIELD": [
                        '숫자 필드 생성',
                        '필드명 입력: ',
                        ''
                    ],
                }
            if job_index == 5:
                option = {
                    "apply_basic_qss": True,

                    "disable_file_type_layer": True,
                    "disable_file_type_shp": True,
                    "disable_file_type_json": True,
                    "disable_file_type_txtcsv": True,
                    "disable_file_type_fold": False,

                    "show_uid_in_file": False,
                    "show_tuid_in_file": False,
                    "show_field_in_file": True,

                    "setting_by_text": False,
                    "setting_by_array": False,
                    "setting_by_expression": False,
                    "setting_by_section": {"enabled": False, "value_type": "int"},
                    "setting_by_numeric": {"enabled": False, "value_type": "int"},
                    "setting_by_combo": {"enabled": False, "items": []},

                    "output_by_file": True,
                    "output_by_field": False,
                    "output_by_table": False,

                    "FILE_FIELD": [
                        '필드 순서 변경',
                        '필드 선택: ',
                        "출력 순서를 기준으로 모든 필드를 순서대로 선택해 주세요."
                    ],
                }
            if job_index == 6:
                option = {
                    "apply_basic_qss": True,

                    "disable_file_type_layer": True,
                    "disable_file_type_shp": True,
                    "disable_file_type_json": True,
                    "disable_file_type_txtcsv": True,
                    "disable_file_type_fold": False,

                    "show_uid_in_file": False,
                    "show_tuid_in_file": True,
                    "show_field_in_file": False,

                    "setting_by_text": False,
                    "setting_by_array": False,
                    "setting_by_expression": False,
                    "setting_by_section": {"enabled": False, "value_type": "int"},
                    "setting_by_numeric": {"enabled": False, "value_type": "int"},
                    "setting_by_combo": {"enabled": False, "items": []},

                    "output_by_file": True,
                    "output_by_field": True,
                    "output_by_table": False,

                    "FILE_TUID": [
                        '복사할 필드 선택',
                        '필드 선택: ',
                        '새 필드로 복제할 대상 필드를 선택해 주세요.'
                    ],

                    "RESULT_FIELD": [
                        '필드 복사 결과 저장',
                        '필드명 입력: ',
                        ''
                    ],
                }
            return option

        except Exception as e:
            logger.error("에러 발생: %s", e, exc_info=True)

    def run_job_by_index(self, gdf, file_preview_index):
        
        try:
            
            file_info = common.fileInfo_1

            
            setting_text = file_info.file_setting.get_text()
            setting_numeric = file_info.file_setting.get_numeric()
            setting_section_min, setting_section_max = file_info.file_setting.get_section()
            setting_combo = file_info.file_setting.get_combo()
            setting_array_string, setting_array_integer, setting_array_float = file_info.file_setting.get_array()

            
            source_file_type, source_file_path, source_file_name = file_info.file_record.get_record()

            
            file_preview = file_info.file_preview[file_preview_index]
            file_field_selection = file_preview.get_selection_field()
            file_tuid = file_preview.get_file_tuid()
            file_is_field_check = file_preview.get_field_check()
            result_field = file_info.result_field

            
            gdf.columns = gdf.columns.astype(str)

            
            result = None
            if self.job_index == 0:
                result = self.generate_sequential_id_field(gdf, result_field)

            elif self.job_index == 1:
                result = self.generate_random_digit_ids(gdf, int(float(setting_text)), result_field)

            elif self.job_index == 2:
                result = self.add_empty_string_field(gdf, result_field, setting_text)

            elif self.job_index == 3:
                result = self.rename_field(gdf, file_tuid, setting_text)

            elif self.job_index == 4:
                result = self.convert_field_to_numeric_auto(gdf, file_tuid, result_field)

            elif self.job_index == 5:
                result = self.reorder_fields(gdf, file_field_selection)

            elif self.job_index == 6:
                result = self.copy_field_values(gdf, file_tuid, result_field)

            
            if result is None or result is False:
                return None

            return result

        except Exception as e:
            logger.error("에러 발생: %s", e, exc_info=True)
            return None




