import asyncio
import logging
from datetime import datetime
from enum import Enum
from typing import Dict, List

from sqlalchemy.orm import Session

from src.apps.match.enums import MatchedType, Status
from src.apps.match.services.logs_service import *
from src.apps.match.services.matcher_service import *
from src.apps.match.services.output_service import *

logger = logging.getLogger(__name__)

# Dependency injection
matcher_service = MatcherService()
output_service = OutputService()
logs_service = LogsService()


# Core match job logic
async def wine_match_job(
    db: Session, codes: List[str], run_keywords: List[bool], dates: List[datetime], mode: str = None
):
    print(f"Starting Wine Match Job with codes: {codes}, run_keywords: {run_keywords}, dates: {dates}, mode: {mode}")
    start_time = datetime.now()

    keyword_codes: Dict[str, datetime] = {}
    history_codes: Dict[str, datetime] = {}

    for i, code in enumerate(codes):
        match_type = MatchedType.KEYWORD if run_keywords[i] else MatchedType.HISTORY
        date = datetime.strptime(dates[i], "%Y-%m-%d")

        if match_type == MatchedType.KEYWORD:
            keyword_codes[code] = date
        else:
            history_codes[code] = date

        matcher_service.add_to_running_matches(code, match_type)

    # Process history matches concurrently
    async def process_history(db: Session, code: str, date: datetime):
        if not matcher_service.is_terminated_match(code, MatchedType.HISTORY):
            if output_service.is_valid_crawl_output(code, date):
                logs_service.save_match_log(db, code, date, False, Status.RUNNING, start_time)
                await matcher_service.execute(db, code, False, date)
            else:
                logger.warning(f"[{code}] match input not found at: {date}")
            matcher_service.remove_from_running_matches(code, MatchedType.HISTORY)
        else:
            logger.warning(f"[{code}] was terminated from history match.")

    # Concurrent execution
    await asyncio.gather(*(process_history(db, k, v) for k, v in history_codes.items()))

    # Process keyword matches sequentially (or use asyncio.gather here too)
    for k, v in keyword_codes.items():
        if not matcher_service.is_terminated_match(k, MatchedType.KEYWORD):
            if output_service.is_valid_crawl_output(k, v):
                logs_service.save_match_log(db, k, v, True, Status.RUNNING, start_time)
                matcher_service.execute(db, k, True, v)
            else:
                logger.warning(f"[{k}] match input not found at: {v}")
            matcher_service.remove_from_running_matches(k, MatchedType.KEYWORD)
        else:
            logger.warning(f"[{k}] was terminated from keyword match.")

    duration = datetime.now() - start_time
    logger.info(f"Wine Match Job completed. Execution time: {duration}")
