# -*- coding: utf-8 -*-
"""
STEP104-01 PublishSession

역할:
- 한 번의 블로그 발행 작업을 하나의 Session으로 표현한다.
- 현재 단계, 시작/종료 시간, 처리 결과를 보관한다.
- BehaviorLogger와 함께 사용한다.
"""

import time
import uuid
from contextlib import contextmanager
from datetime import datetime


class PublishSession:
    def __init__(
        self,
        pipeline_id=None,
        realtor_id=None,
        publish_queue_id=None,
        article_no=None,
        draft_id=None,
        actor_name="default",
        profile_name="default",
    ):
        self.session_id = f"hpe-{uuid.uuid4().hex}"
        self.pipeline_id = pipeline_id
        self.realtor_id = realtor_id
        self.publish_queue_id = publish_queue_id
        self.article_no = article_no
        self.draft_id = draft_id

        self.actor_name = actor_name
        self.profile_name = profile_name

        self.current_step = None
        self.started_at = datetime.now()
        self.finished_at = None

        self.success = None
        self.result_url = None
        self.error_message = None

        self.events = []

    def mark_success(self, result_url=None):
        self.success = True
        self.result_url = result_url
        self.finished_at = datetime.now()

    def mark_failed(self, error_message):
        self.success = False
        self.error_message = str(error_message)
        self.finished_at = datetime.now()

    @contextmanager
    def step(self, name, logger=None, meta=None):
        self.current_step = name
        started = time.time()
        started_at = datetime.now()

        event = {
            "name": name,
            "status": "running",
            "started_at": started_at,
            "finished_at": None,
            "elapsed_ms": None,
            "error_message": None,
            "meta": meta or {},
        }
        self.events.append(event)

        if logger:
            logger.start_behavior(self, name, meta=meta)

        try:
            yield event
            elapsed_ms = int((time.time() - started) * 1000)
            event["status"] = "success"
            event["finished_at"] = datetime.now()
            event["elapsed_ms"] = elapsed_ms

            if logger:
                logger.finish_behavior(self, name, success=True, elapsed_ms=elapsed_ms, meta=meta)

        except Exception as e:
            elapsed_ms = int((time.time() - started) * 1000)
            event["status"] = "failed"
            event["finished_at"] = datetime.now()
            event["elapsed_ms"] = elapsed_ms
            event["error_message"] = str(e)

            if logger:
                logger.finish_behavior(
                    self,
                    name,
                    success=False,
                    elapsed_ms=elapsed_ms,
                    error_message=str(e),
                    meta=meta,
                )
            raise

    def elapsed_seconds(self):
        end = self.finished_at or datetime.now()
        return (end - self.started_at).total_seconds()

    def to_dict(self):
        return {
            "session_id": self.session_id,
            "pipeline_id": self.pipeline_id,
            "realtor_id": self.realtor_id,
            "publish_queue_id": self.publish_queue_id,
            "article_no": self.article_no,
            "draft_id": self.draft_id,
            "actor_name": self.actor_name,
            "profile_name": self.profile_name,
            "current_step": self.current_step,
            "started_at": self.started_at,
            "finished_at": self.finished_at,
            "success": self.success,
            "result_url": self.result_url,
            "error_message": self.error_message,
            "elapsed_seconds": self.elapsed_seconds(),
            "events": self.events,
        }
