import json
import random
import re

from flask import flash, redirect, session, url_for
import pandas as pd
from static.data.damage_solutions import damage_solutions
from utils.common import classify_repair, get_db_connection, normalize_damage, sort_components, clean_dataframe_data
from utils.damage_utils import natural_sort_key
from bs4 import BeautifulSoup


def natural_sort_key_positions(positions):
    """부재위치를 자연 정렬 (s1, s2, s3... s10, s11... 순서로)"""
    import re
    def sort_key(position):
        parts = re.split(r'(\d+)', str(position))
        return [int(part) if part.isdigit() else part.lower() for part in parts]
    return sorted(positions, key=sort_key)


def merge_girder_positions_for_pivot(group):
    """거더 내부/외부 데이터를 통합"""
    merged_data = []
    position_map = {}
    
    for _, row in group.iterrows():
        position = row['부재위치']
        # s1i, s1o -> s1으로 통합
        base_position = re.sub(r'[io]$', '', str(position))
        
        if base_position not in position_map:
            position_map[base_position] = {
                '부재명': row['부재명'],
                '부재위치': base_position,
                '손상내용': row['손상내용'],
                '단위': row.get('단위', ''),
                '손상물량': 0,
                '개소': 0,
                '점검면적': row.get('점검면적', 0)
            }
        
        # 데이터 통합
        position_map[base_position]['손상물량'] += row['손상물량']
        position_map[base_position]['개소'] += row['개소']
        position_map[base_position]['점검면적'] = max(
            position_map[base_position]['점검면적'], 
            row.get('점검면적', 0)
        )
    
    # DataFrame으로 변환
    for data in position_map.values():
        merged_data.append(data)
    
    return pd.DataFrame(merged_data)


COMPONENT_ORDER = [
    "바닥판", "슬래브",
    "거더", "주형",
    "가로보", "세로보", "격벽",
    "교대",
    "교각",
    "교량받침",
    "신축이음", "신축",
    "교면포장", "포장",
    "배수시설", "배수구",
    "난간", "연석", "방호벽", "방호울타리", "중대", "방음벽", "방음판",
    "점검시설", "점검", "점검계단"
]

def sort_components(components):
    def component_key(name):
        for idx, keyword in enumerate(COMPONENT_ORDER):
            if keyword in name:
                return idx
        return len(COMPONENT_ORDER)
    return sorted(components, key=component_key)


def pivot_detail_view(filename, pivot,detail=True):
    conn = get_db_connection()
    cur = conn.cursor()
    cur.execute(
        "SELECT file_data FROM uploaded_files WHERE filename = %s AND user_id = %s",
        (filename, session['user_id'])
    )
    result = cur.fetchone()
    
    if not result:
        flash('파일을 찾을 수 없습니다.')
        return redirect(url_for('index'))
        
    # JSON 데이터를 DataFrame으로 변환
    file_data = result[0]
    if isinstance(file_data, str):
        file_data = json.loads(file_data)
    df = pd.DataFrame(file_data)
    
    # DataFrame 데이터 정리 및 trim 처리
    df = clean_dataframe_data(df)
    
    #df["손상내용"] = df["손상내용"].replace("0.3", df["균열폭 으로 시작하는 컬럼"], regex=True)
    
     
    if detail:
        df['손상내용'] = df['손상내용'].str.replace(r'\(([\d.]+㎜)미만\)', r'(\1)', regex=True)
        df['손상내용'] = df['손상내용'].str.replace(r'\(([\d.]+㎜)이상\)', r'(\1)', regex=True)
 
        # '균열폭'으로 시작하는 컬럼 찾기
        crack_cols = [col for col in df.columns if col.startswith('균열폭')]
        if crack_cols:
            crack_col = crack_cols[0]  # 첫 번째 '균열폭' 컬럼 사용
        
            # '손상내용'이 '균열(숫자m)' 또는 '균열(숫자㎜)' 패턴인 행을 찾아, '균열(균열폭값)'으로 치환
            mask = df['손상내용'].str.match(r'균열\([\d.]+[m㎜]\)', na=False)
            df.loc[mask, '손상내용'] = '균열(' + df.loc[mask, crack_col].astype(str) + 'mm)'
    
        
    
    
    # 손상내용명에 '받침' 또는 '전단키'가 포함된 경우 부재명을 '교량받침'으로 변경
    bearing_damage_mask = (df['손상내용'].str.contains('받침', na=False) | 
                          df['손상내용'].str.contains('전단키', na=False))
    
    
    
    # 해당 데이터의 부재명을 '교량받침'으로 변경
    df.loc[bearing_damage_mask, '부재명'] = '교량받침'
    
    # 부재명 정렬
    unique_components = sort_components(df['부재명'].unique())
    df = df[df['부재명'].isin(unique_components)]
    
    # 데이터 처리 및 HTML 생성
    detail_html = ""
    detail_html_header_link = ""
    for name in unique_components:
        group = df[df['부재명'] == name]
        if group.empty:
            continue
        
        # 거더인 경우 내부/외부 데이터 통합
        #if '거더' in name:
        #    group = merge_girder_positions_for_pivot(group)
        #    if group.empty:
        #        continue
        
        header1 = '부재위치'
        colum1 = '손상내용'
        if pivot:   
            header1 = '손상내용'
            colum1 = '부재위치'
        
        # 자연 정렬 적용
        header1_value = natural_sort_key_positions(group[header1].unique())
        colum1_value = group[colum1].unique()

        columns = pd.MultiIndex.from_product(
            [header1_value, ['손상물량', '개소']],
        )
        table = pd.DataFrame('', index=colum1_value, columns=columns)
        
        # 모든 손상물량 합계
        total_dmg_sum = 0
        total_cnt_sum = 0

        for dmg in colum1_value:
            sub = group[group[colum1] == dmg]

            for pos in header1_value:
                match = sub[sub[header1] == pos]

                if not match.empty:
                    dmg_val = round(match['손상물량'].sum(), 2)
                    cnt_val = int(match['개소'].sum())
                    table.loc[dmg, (pos, '손상물량')] = dmg_val
                    table.loc[dmg, (pos, '개소')] = cnt_val
                else:
                    table.loc[dmg, (pos, '손상물량')] = "-"
                    table.loc[dmg, (pos, '개소')] = "-"

            # 위치별 중복 제거 후 합산
            total_dmg = sub.groupby(header1)['손상물량'].sum().sum()
            total_cnt = sub.groupby(header1)['개소'].sum().sum()

            table.loc[dmg, ('합계', '손상물량')] = round(total_dmg, 2)
            table.loc[dmg, ('합계', '개소')] = str(int(total_cnt))

            total_dmg_sum += total_dmg
            total_cnt_sum += total_cnt

        # 단위 값 처리
        try:
            if pivot:
                # 피봇이 활성화된 경우 (손상내용이 컬럼이 됨)
                unit_values = []
                for pos in header1_value:
                    damage_rows = group[group['손상내용'] == pos]
                    if not damage_rows.empty and '단위' in damage_rows.columns:
                        unit_values.append(damage_rows['단위'].values[0])
                    else:
                        unit_values.append('')
            else:
                # 피봇이 비활성화된 경우 (부재위치가 컬럼이 됨)
                unit_values = []
                for dmg in colum1_value:
                    damage_rows = group[group['손상내용'] == dmg]
                    if not damage_rows.empty and '단위' in damage_rows.columns:
                        unit_values.append(damage_rows['단위'].values[0])
                    else:
                        unit_values.append('')
        except Exception as e:
            # 오류 발생 시 빈 값으로 채움
            print(f"단위 값 처리 중 오류 발생: {e}")
            unit_values = ['' for _ in range(len(header1_value) if pivot else len(colum1_value))]
         
        # 열 이름 리스트 추출
        col_list = list(table.columns)
        
        # '합계' 관련 컬럼 중 '손상물량'이 있는 첫 위치 찾기
        sum_idx = next((i for i, col in enumerate(col_list)
                        if isinstance(col, tuple) and col[0] == '합계' and col[1] == '손상물량'), len(col_list))
        # 해당 위치에 단위 열 삽입
        if not pivot: 
           table.insert(sum_idx, '단위', unit_values)
        
        # 부재명과 손상내용 열 삽입
        table.insert(0, '부재명', [name] * len(colum1_value))
        
        if pivot:
            table.insert(1, '경간', colum1_value)
        else:
            table.insert(1, '손상내용', colum1_value)
        
        # 비어 있는 셀은 - 처리
        table = table.fillna("-")
        
        table.loc['합계', :] = ['합계'] * len(table.columns)

        for pos in header1_value:
            pos_dmg_sum = 0
            pos_cnt_sum = 0
            for dmg in colum1_value:
                dmg_val = table.loc[dmg, (pos, '손상물량')]
                cnt_val = table.loc[dmg, (pos, '개소')]

                if dmg_val != "-" and dmg_val != "":
                    pos_dmg_sum += float(dmg_val)
                if cnt_val != "-" and cnt_val != "":
                    pos_cnt_sum += int(cnt_val)

            table.loc['합계', (pos, '손상물량')] = round(pos_dmg_sum, 2)
            table.loc['합계', (pos, '개소')] = int(pos_cnt_sum)

        # 전체 합계 칸
        table.loc['합계', ('합계', '손상물량')] = round(total_dmg_sum, 2)
        table.loc['합계', ('합계', '개소')] = int(total_cnt_sum)
        
        html_table = table.to_html(classes='table-bordered table-striped', index=False, border=0, justify='left')
 
        soup = BeautifulSoup(html_table, "html.parser")
        rows = soup.find_all('tr')
        
        first_td = rows[2].find('td')
        first_td['rowspan'] = str(len(table))
        for tr in rows[3:]:
            tr.find('td').decompose()
            
        # 첫 번째 행의 th 셀들을 가져옵니다.
        first_row_ths = rows[0].find_all("th")

        # 첫 번째 열(th)을 병합
        first_th = first_row_ths[0]
        first_th['rowspan'] = 2

        # 두 번째 열(th)을 병합
        second_th = first_row_ths[1]
        second_th['rowspan'] = 2
        if not pivot:
            end_th = first_row_ths[len(first_row_ths)-2]
            end_th['rowspan'] = 2

        # 두 번째 행의 해당 열(th)들을 제거
        second_row_ths = rows[1].find_all("th")
        second_row_ths[0].decompose()
        second_row_ths[1].decompose()
        
        if not pivot:
            second_row_ths[len(second_row_ths)-3].decompose()

        html_table = str(soup)
        if pivot:
            soup = BeautifulSoup(html_table, "html.parser")
            rows = soup.find_all('tr') 
             
            first_row_ths = [th for th in rows[1].find_all("th") if "손상물량" in th.get_text(strip=True)]
            i = 0
            z = 0
            
            for th in first_row_ths[0:len(first_row_ths)-1]:
                header_text = th.get_text(strip=True)
                unit = unit_values[i]
                th.string = f"{header_text} ({unit})"
                
                #if z % 2 == 0:  # i가 짝수일 때
                i += 1
                z += 1
            html_table = str(soup)
    
        unique_damages = sorted(set(group['손상내용']))
        damage_text = ', '.join(unique_damages)
        summary = f"<p class='observation-summary'>{name}에 대한 외관조사결과에서 조사된 바와 같이, {damage_text} 등의 손상이 조사되었다.</p>"
        #detail_html_header_link += f"<a href=\"#header_{name}\">🔗 {name} </a>"
        # ...existing code...
        detail_html_header_link += (
            f'<a href="#header_{name}" '
            'class="btn btn-outline-primary btn-sm m-1" '
            'style="background-color:#1976d2; color:#fff; border:none;">'
            f'🔗 {name}</a>'
        )

        #detail_html += f"<h4 id=\"header_{name}\">📌 부재명: {name}</h4>{summary}"
        
                # ...existing code...
        # ...existing code...
        detail_html += (
            f'<div style="display:flex;justify-content:space-between;align-items:center;">'
            f'<h4 id="header_{name}" style="margin-bottom:0; scroll-margin-top:80px;">📌 부재명: {name}</h4>'
            f'<a href="#top" class="btn btn-light btn-sm" '
            'style="background-color:#f5f5f5; color:#1976d2; border:0px solid #1976d2; font-weight:bold; box-shadow:0 1px 4px rgba(25,118,210,0.08);">'
            '▲ 맨 위로</a>'
            f'</div>'
            f'{summary}'
        )
# ...existing code...
        # ...existing code...

        detail_html += "<style>table.table-bordered { margin-left: 0 !important; width: auto !important; } table.table-bordered td { text-align: center !important; }</style><div class='table-container' >"
        detail_html += html_table
        detail_html += "</div>"
        # 손상내용별 설명 추가
        detail_html += "<h5>🛠 손상별 원인 및 대책방안</h5><ul>"
        
        for dmg in group['손상내용'].unique():
            repair_method = classify_repair(dmg)
            detail_html += f"<p><strong>🔸 손상내용: {dmg} (보수방안: {repair_method})</strong></p><ul>"
            try:
                # 손상내용 정규화 (띄어쓰기 제거 및 유사어 처리)
                normalized_dmg = normalize_damage(dmg)
                
                # 균열 관련 처리
                if '균열' in normalized_dmg and not any(x in normalized_dmg for x in ['백태', '누수', '부']):
                    # 균열 크기 패턴 확인 (숫자 + mm 또는 ㎜, cw 등 접두사와 등호 포함)
                    if re.search(r'균열\(?[a-zA-Z]*=?[\d.]+(mm|㎜)', normalized_dmg):
                        # 균열 설명 사용
                        if "균열" in damage_solutions:
                            selected_solutions = random.sample(damage_solutions["균열"], 2)
                            for solution in selected_solutions:
                                formatted_solution = solution.replace('{name}', name).replace('{보수방안}', repair_method)
                                detail_html += f"<li>{formatted_solution}</li>"
                # 다른 손상 유형 처리
                elif normalized_dmg in damage_solutions and len(damage_solutions[normalized_dmg]) >= 2:
                    selected_solutions = random.sample(damage_solutions[normalized_dmg], 2)
                    for solution in selected_solutions:
                        formatted_solution = solution.replace('{name}', name).replace('{보수방안}', repair_method)
                        detail_html += f"<li>{formatted_solution}</li>"
            except Exception:
                pass
            detail_html += "</ul>"
            detail_html += "<hr>"
        
        detail_html += "</ul>"
    
    return detail_html ,detail_html_header_link
