"""
create_custom_asset.py - AWS DataZone에 Tableau 대시보드 자산을 생성하는 스크립트

이 스크립트는 다음 기능을 수행합니다:
1. Tableau 데이터베이스에서 대시보드 정보를 조회
2. 조회된 대시보드 정보를 기반으로 AWS DataZone에 자산 생성
3. 생성된 자산 ID 반환 (이후 메타데이터 및 계보 정보 업데이트에 사용)

사용법:
    python create_custom_asset.py
""" 
    
import boto3
import json
import psycopg2
from psycopg2.extras import RealDictCursor
from datetime import datetime
    
# 설정 상수 정의
AWS_REGION = '{AWS Region 입력}'
# Amazon DataZone의 도메인에서 생성한 dashboard 프로젝트를 클릭하면, 브라우저 주소창(URL)에서 <도메인 ID>와 <프로젝트 ID>를 확인할 수 있습니다. 
# 예시) https://<도메인 ID>.datazone.<Region>.on.aws/projects/<프로젝트 ID>/overview
DATAZONE_DOMAIN_ID = '{DataZone 도메인 ID 입력}' 
DATAZONE_PROJECT_ID = '{DataZone 프로젝트 ID 입력}'  
DATAZONE_ASSET_TYPE = 'dashboard_asset_type'        # 생성한 자산 유형 이름
DB_SECRET_NAME = ''                                 # (선택사항) Tableau 서버에 연결해서 대시보드 정보를 로드하기 위한 DB 연결 정보가 저장된 Secret 이름

# AWS 클라이언트 초기화
datazone_client = boto3.client('datazone', region_name=AWS_REGION)
secrets_client = boto3.client('secretsmanager', region_name=AWS_REGION)

def get_db_connection_params(secret_name):
    """
    AWS Secrets Manager에서 데이터베이스 접속 정보를 가져옵니다.
    
    Args:
        secret_name (str): Secrets Manager에 저장된 시크릿 이름
        
    Returns:
        dict: 데이터베이스 접속 파라미터 딕셔너리
    """
    secret = json.loads(secrets_client.get_secret_value(SecretId=secret_name)['SecretString'])

    # 연결 파라미터 구성
    db_params = {
        'host': secret['host'],
        'port': secret['port'],
        'database': secret['dbname'],
        'user': secret['username'],
        'password': secret['password']
    }

    return db_params


def run_query(secret_name, query, params=None):
    """
    AWS Secrets Manager에서 DB 접속 정보를 가져와 쿼리를 실행합니다.
    
    Args:
        secret_name (str): Secrets Manager에 저장된 시크릿 이름
        query (str): 실행할 SQL 쿼리
        params (tuple, optional): 쿼리 파라미터. 기본값은 None.
        
    Returns:
        list: 쿼리 결과를 딕셔너리 리스트 형태로 반환
    """
    # DB 접속 정보 가져오기
    db_params = get_db_connection_params(secret_name)

    # 연결 및 쿼리 실행
    with psycopg2.connect(**db_params) as conn, conn.cursor(cursor_factory=RealDictCursor) as cur:
        cur.execute(query, params)
        return cur.fetchall()


def load_dashboard_data():
    """
    Tableau 데이터베이스에서 대시보드 정보를 로드합니다.
    
    Returns:
        list: 대시보드 정보를 딕셔너리 리스트 형태로 반환
    """
    query = """
        SELECT 
            s.name AS site_name,
            w.id AS id,
            w.name AS name,
            w.description AS description,
            w.created_at AS created_at,
            w.updated_at AS updated_at,
            u.username AS owner
        FROM _workbooks w
        LEFT JOIN sites s ON w.site_id = s.id
        LEFT JOIN users u ON w.owner_id = u.id
    """
    dashboards = run_query(DB_SECRET_NAME, query)
    return dashboards



def create_dashboard_asset(dashboard_info):
    """
    대시보드 정보를 기반으로 DataZone에 커스텀 자산을 생성합니다.
    
    Args:
        dashboard_info (dict): 대시보드 정보 딕셔너리
        
    Returns:
        str: 생성된 자산의 ID
    """

    # 자산 이름 설정
    asset_name = dashboard_info['name']

    # 자산 설명 설정 (description이 있는 경우에만 사용)
    asset_description = dashboard_info.get('description', '') or ''

    # 자산 생성 API 호출
    response = datazone_client.create_asset(
        domainIdentifier=DATAZONE_DOMAIN_ID,
        formsInput=[],
        name=asset_name,
        description=asset_description,
        owningProjectIdentifier=DATAZONE_PROJECT_ID,
        predictionConfiguration={
            'businessNameGeneration': {
                'enabled': False
            }
        },
        typeIdentifier=DATAZONE_ASSET_TYPE
    )

    asset_id = response['id']
    print(f"생성된 자산: '{asset_name}' (ID: {asset_id})")

    return asset_id

def main():
    """
    메인 실행 함수 - 대시보드 데이터를 로드하고 DataZone 자산으로 등록합니다.
    """
    try:
        print("Tableau 대시보드 자산 생성 시작...")

        # 실제 환경에서는 다음 코드 사용:
        # dashboards = load_dashboard_data()

        # 테스트용 예시 데이터:
        dashboards = [
            {
                'site_name': 'analytics',
                'id': '1',
                'name': 'Sales Performance Dashboard',
                'description': '목표 대비 판매 실적을 분석하고 매장별, 제품별, 기간별 성과를 시각화하는 대시보드',
                'created_at': datetime.now(),
                'updated_at': datetime.now(),
                'owner': '영업팀_홍길동'
            },
            # 추가 대시보드 데이터는 여기에 추가
        ]

        # 생성된 자산 ID를 저장할 딕셔너리 (dashboard_id: asset_id)
        created_assets = {}

        # 각 대시보드에 대해 자산 생성
        for dashboard in dashboards:
            dashboard_id = dashboard['id']
            asset_id = create_dashboard_asset(dashboard)

            # 추후 메타데이터 업데이트 및 계보 작성을 위해 dashboard_id와 asset_id 매핑 저장
            created_assets[dashboard_id] = asset_id

        print(f"생성된 자산 총 개수: {len(created_assets)}")
        print("자산 생성 완료")

        # 추후 확장을 위해 생성된 자산 매핑 반환
        return created_assets

    except Exception as e:
        print(f"자산 등록 중 오류 발생: {str(e)}")
        return {}

if __name__ == "__main__":
    main()
                 