# [2023/10/16 빌드] ~ [2026/01/28 최적화 업데이트]
import subprocess
import sys
import os
import shutil
import json
import requests
import pyperclip
import pandas as pd
import pytesseract
import ctypes
from datetime import datetime
from time import sleep

# [자동 설치 로직] 필요한 라이브러리가 없으면 자동으로 pip install을 실행합니다.
required_libraries = [
    'colorama', 'selenium', 'pytesseract', 'pyperclip', 
    'requests', 'jira', 'pandas', 'openpyxl'
]

for lib in required_libraries:
    try:
        if lib == 'jira':
            import jira
        elif lib == 'openpyxl':
            import openpyxl
        else:
            __import__(lib)
    except ImportError:
        print(f"[RPA System] '{lib}' 모듈이 없어 설치를 진행합니다...")
        subprocess.check_call([sys.executable, "-m", "pip", "install", lib])
        print(f"[RPA System] '{lib}' 설치가 완료되었습니다.")

from myinfo import *
from colorama import init, Back, Fore, Style
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.alert import Alert
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait, Select
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoAlertPresentException, TimeoutException
from selenium.webdriver.common.keys import Keys
from jira import JIRA

# colorama 초기화
init(autoreset=True)

# --- 전역 변수 및 초기화 ---
now = datetime.now()
today = datetime.today().strftime('%Y-%m-%d')
date_mdhm = now.strftime('%m%d%H%M')
temp_folder = 'c:/rpa_temp/'

if os.path.isdir(temp_folder):
    for file in os.listdir(temp_folder):
        try:
            shutil.rmtree(temp_folder)
        except:
            pass
if not os.path.exists(temp_folder):
    os.makedirs(temp_folder)

# --- 공통 유틸리티 함수 ---

def current_time():
    now = datetime.now()
    return now.strftime("[%Y-%m-%d %H:%M:%S]")

def handle_alert(driver):
    while True:
        try:
            alert = driver.switch_to.alert
            alert.accept()
            break
        except:
            sleep(1)

def handle_loading(driver):
    while True:
        try:
            alert = driver.switch_to.alert
            break
        except NoAlertPresentException:
            try:
                WebDriverWait(driver, 1).until_not(EC.presence_of_element_located((By.ID, 'loading')))
                sleep(1)
                break
            except TimeoutException:
                continue

def get_text_after_pattern(pattern):
    patterns = {"PRD": "", "QA": "qt-", "QA2": "qt2-"}
    return patterns.get(pattern)

def get_common_chrome_options():
    """크롬 브라우저 옵션 설정 공통화"""
    options = Options()
    options.add_argument("--start-maximized")
    options.add_argument("--disable-features=InsecureDownloadWarnings")
    options.add_experimental_option('detach', True)
    options.add_experimental_option('excludeSwitches', ['enable-logging'])
    options.add_experimental_option('prefs', {
        'download.default_directory': r'C:\rpa_temp',
        'safebrowsing.enabled': 'False'
    })
    return options

# --- 로그인 로직 리팩토링 (핵심 엔진) ---

def _core_prd_login_process(driver, final_destination):
    """PRD 서버의 복잡한 OTP 로그인 로직 통합 엔진"""
    ep_url = 'http://newep.lge.com/portal/main/portalMain.do'
    driver.get(ep_url)
    
    WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.ID, 'USER')))
    sleep(1)
    driver.find_element(By.ID, 'USER').send_keys(EPID)
    driver.find_element(By.ID, 'LDAPPASSWORD').send_keys(EPPW)
    driver.implicitly_wait(2)
    driver.find_element(By.ID, 'OTP').click()

    # 창 전환 1 (ID/PW 재입력)
    WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))
    driver.switch_to.window(driver.window_handles[1])
    driver.find_element(By.ID, 'pw').send_keys(EPPW)
    driver.find_element(By.ID, 'myButton').click()

    # 창 전환 2 (인증 선택)
    sleep(1)
    WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))
    driver.switch_to.window(driver.window_handles[1])
    driver.find_element(By.XPATH, '//*[@id="TA_01"]/div[4]/div[1]').click()
    
    # 창 전환 3 (OCR 인식)
    WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(3))
    driver.switch_to.window(driver.window_handles[2])

    while True:
        try:
            driver.refresh()
            element1 = driver.find_element(By.ID, 'photo_imageK')
            element1.screenshot("otpimg.png")
            pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract'
            otpimg = pytesseract.image_to_string(r'otpimg.png').replace(" ", "").strip()
            
            driver.find_element(By.ID, 'bizidK').send_keys(XID)
            driver.find_element(By.ID, 'pcodeK').send_keys(BDAY)
            driver.find_element(By.ID, 'answerK').send_keys(otpimg)
            driver.find_element(By.XPATH, '//*[@id="form1"]/div[1]/table/tbody/tr[8]/td/input[1]').click()
            sleep(2)
            try:
                alert = driver.switch_to.alert
                print("[RPA] OTP 인식 오류, 재시도 합니다.")
                alert.accept()
            except:
                print("[RPA] OTP 정상 입력.")
                break
        except:
            pass

    # 최종 OTP 코드 획득
    WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(4))
    driver.switch_to.window(driver.window_handles[3])
    OTPD = driver.find_element(By.XPATH, '//*[@id="loadingK"]/b').text
    
    # 불필요한 창 닫기
    for i in range(3, 0, -1):
        driver.switch_to.window(driver.window_handles[i])
        driver.close()
    
    driver.switch_to.window(driver.window_handles[0])
    driver.find_element(By.ID, 'OTPPASSWORD').send_keys(OTPD)
    driver.find_element(By.ID, 'loginSsobtn').click()
    sleep(1)
    
    while True:
        try:
            driver.get(ep_url)
            sleep(0.5)
            driver.find_element(By.ID, 'USER').send_keys(EPID)
            input(f'{Fore.RED}[ERROR] 로그인 오류, 수동 로그인 후 엔터키 입력..{Style.RESET_ALL}')
        except:
            driver.get(final_destination)
            break
    return driver

# --- 외부 호출용 로그인 함수 (함수명 유지) ---

def sdp_login(target_server, target_url=None):
    server_url = get_text_after_pattern(target_server)
    url = f'http://{server_url}kic.smartdesk.lge.com/admin/main.lge'
    final_destination = target_url if target_url else url
    options = get_common_chrome_options()

    if target_server == 'PRD':
        print(f'[RPA] 운영 서버에 {EPID} 계정으로 로그인 합니다.')
        options.page_load_strategy = 'none'
        driver = webdriver.Chrome(options=options)
        return _core_prd_login_process(driver, final_destination)
    else:
        print(f'[RPA] {target_server} 서버에 {QAID} 계정으로 로그인 합니다.')
        driver = webdriver.Chrome(options=options)
        driver.get(url)
        handle_alert(driver)
        driver.find_element(By.ID, 'USER').send_keys(QAID)
        driver.find_element(By.ID, 'LDAPPASSWORD').send_keys(QAPW)
        driver.find_element(By.ID, 'loginSsobtn').click()
        try:
            WebDriverWait(driver, 3).until(EC.alert_is_present())
            driver.switch_to.alert.dismiss()
        except:
            pass
        driver.get(final_destination)
        return driver

def ep_prd_login(target_url):
    print(f'[RPA] 운영 서버에 {EPID} 계정으로 로그인 합니다.')
    options = get_common_chrome_options()
    options.page_load_strategy = 'none'
    driver = webdriver.Chrome(options=options)
    return _core_prd_login_process(driver, target_url)

def create_webbrowser():
    options = get_common_chrome_options()
    return webdriver.Chrome(options=options)

# --- 기타 조작 및 시스템 함수 ---

def find_e(driver, locator, action, value=None, index=0, timeout=10, max_tries=3):
    """오브젝트 조작 (index 기본값 0으로 리팩토링)"""
    for i in range(max_tries):
        try:
            elements = WebDriverWait(driver, timeout).until(EC.presence_of_all_elements_located(locator))
            element = elements[index] if index is not None else elements[0]
            if action == 'click': element.click()
            elif action == 'send_keys': element.send_keys(value)
            elif action == 'clear': element.clear()
            else: raise ValueError(f"Unsupported action '{action}'")
            break
        except TimeoutException:
            print(current_time(), f"Timeout {locator}, attempt {i+1}/{max_tries}")
    else:
        print(current_time(), f"Failed to locate element after {max_tries} tries")

def rpa_progress(status):
    file_name = os.path.basename(sys.argv[0])
    print('\n[RPA] ' + current_time() + ' ' + file_name + ' ' + status)
    return file_name

# 화면 보호기 및 전원 설정
ES_CONTINUOUS = 0x80000000
ES_DISPLAY_REQUIRED = 0x00000002
SetThreadExecutionState = ctypes.windll.kernel32.SetThreadExecutionState

def prevent_screensaver():
    return SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED)

def allow_screensaver():
    return SetThreadExecutionState(ES_CONTINUOUS)

def disable_power_settings():
    os.system("powercfg -change -monitor-timeout-ac 0")
    os.system("powercfg -change -standby-timeout-ac 0")
    os.system("powercfg -change -hibernate-timeout-ac 0")

def enable_power_settings(monitor_timeout, standby_timeout, hibernate_timeout):
    os.system(f"powercfg -change -monitor-timeout-ac {monitor_timeout}")
    os.system(f"powercfg -change -standby-timeout-ac {standby_timeout}")
    os.system(f"powercfg -change -hibernate-timeout-ac {hibernate_timeout}")

# 메시징 및 JIRA 관련 함수
def print_webhook(webhook_url, webhook_data, n_print=None):
    styled_data = (webhook_data
                   .replace('<table border="1" class="dataframe">', '<table border="1" style="border-collapse: collapse;">')
                   .replace('<tr style="text-align: right;">', '<tr style="text-align: center;">')
                   .replace('<th>', '<th style="padding: 4px;color:white;background-color:#000000;text-align:center;font-size:13px;max-width:300px;">')
                   .replace('<td>', '<td style="padding: 4px;font-size:12px;max-width:300px;word-break:break-all;">')
                   .replace('&lt;', '<').replace('&gt;', '>'))
    data = {
        "type": "message",
        "attachments": [{"contentType": "application/vnd.microsoft.card.adaptive",
                         "content": {"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                                     "type": "AdaptiveCard", "version": "1.0",
                                     "body": [{"type": "TextBlock", "text": '🕹 ' + styled_data, "wrap": True}]}}]
    }
    response = requests.post(webhook_url, headers={"Content-Type": "application/json"}, data=json.dumps(data))
    if not n_print: print(styled_data)
    return response

def select_jira_issue(jira, jql_query):
    jira_issues = [issue.key for issue in jira.search_issues(jql_query, maxResults=100)]
    if not jira_issues:
        print(f"{Back.RED}{Fore.WHITE}🚨 검색된 JIRA 이슈가 없습니다.{Style.RESET_ALL}")
        return None
    
    print(f'\n{Back.BLUE}{Fore.WHITE}▪ JIRA 요청 리스트 {Style.RESET_ALL}')
    for idx, issue_key in enumerate(jira_issues, 1):
        issue = jira.issue(issue_key)
        print(f'{Fore.BLUE} {idx}. {issue_key} {issue.fields.summary} {Style.RESET_ALL}')
    
    s = "1" if len(jira_issues) == 1 else input(f' >> 순번 입력 (1~{len(jira_issues)}) : ')
    if not s.isdigit() or int(s) not in range(1, len(jira_issues) + 1):
        return None
    selected_key = jira_issues[int(s) - 1]
    print(f'\n{Fore.YELLOW}{selected_key} 설정을 시작합니다.\n{Style.RESET_ALL}')
    return selected_key

# 데이터 로드 관련 (글로벌 변수 유지)
load_df = None
load_filename = None
load_sheetname = None

def download_jira_attachment(jira, issue_key, temp_folder, extensions=None):
    global load_df, load_filename, load_sheetname
    try:
        jira_issue = jira.issue(issue_key)
        attachments = [(att.filename, att.content) for att in jira_issue.fields.attachment]
        if extensions:
            attachments = [(fn, url) for fn, url in attachments if any(fn.endswith(ext) for ext in extensions)]
        if not attachments: return None, None, None

        load_filename, url = attachments[0] if len(attachments) == 1 else attachments[int(input("파일 번호: "))-1]
        path = os.path.join(temp_folder, load_filename)
        r = jira._session.get(url, stream=True)
        with open(path, 'wb') as f:
            for chunk in r.iter_content(chunk_size=1024): f.write(chunk)

        if load_filename.endswith('.xlsx'):
            xls = pd.ExcelFile(path)
            load_sheetname = xls.sheet_names[0]
            load_df = pd.read_excel(xls, sheet_name=load_sheetname)
            return load_df, load_filename, load_sheetname
    except:
        pass
    return None, None, None

def check_alert(driver, expected_message):
    try:
        WebDriverWait(driver, 60).until(EC.alert_is_present())
        alert = driver.switch_to.alert
        msg = alert.text
        alert.accept()
        return msg
    except:
        return ""