"""
Strategy review and feedback handlers.
"""
import asyncio
import contextlib
import logging
from typing import Dict, Any, Optional

from aiogram import Router, F
from aiogram.enums import ChatAction
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
from aiogram.fsm.context import FSMContext
# StatesGroup and State are not needed here

from src.bot.states.survey import ReviewFSM
from src.bot.services.strategy_service import StrategyService
from src.bot.services.steps_sanitizer import StepsSanitizer
from src.bot.utils.text_utils import strategy_without_day_blocks, extract_day_html
from src.bot.utils.typing_utils import typing_loop
from src.bot.utils.audio_utils import get_audio_info, download_file_bytes, transcribe_bytes_openai
from src.bot.keyboards.daily import kb_daily_step
from src.bot.keyboards.main import kb_strategy_edit_confirm, kb_strategy_overwrite_confirm
from src.bot.keyboards.survey import kb_review
from src.database.db_methods.users import get_user_by_tg
from src.database.db_methods.strategy import create_strategy, ensure_today_issued
from src.database.session import SessionLocal

logger = logging.getLogger(__name__)
router = Router(name="strategy_review")


# ReviewFSM is imported from src.bot.states.survey


@contextlib.asynccontextmanager
async def session_scope():
    """Database session context manager."""
    session = SessionLocal()
    try:
        yield session
        await session.commit()
    except Exception:
        await session.rollback()
        raise
    finally:
        await session.close()


@router.callback_query(F.data == "review:accept")
async def review_accept(cb: CallbackQuery, state: FSMContext):
    """
    Accept strategy and save it to database.
    """
    data = await state.get_data()
    strategy_text: Optional[str] = data.get("draft_strategy_text")
    steps: Dict[str, Any] = data.get("draft_steps") or {}

    if not strategy_text:
        await cb.answer("Стратегия ещё не сгенерирована. Нажми /start и пройди анкету заново.", show_alert=True)
        return

    await cb.answer("Сохраняю…")
    
    async with session_scope() as session:
        user = await get_user_by_tg(session, str(cb.from_user.id))
        if not user:
            await cb.message.answer("Анкета не найдена. Нажми /start и пройди короткую анкету.")
            return

        strat = await create_strategy(
            session,
            user_id=user.id,
            strategy_text=strategy_text,
            steps=steps,
            make_active=True,
            raise_if_active_exists=False,
        )
        await ensure_today_issued(session, strat.id)

    with contextlib.suppress(Exception):
        await cb.message.edit_reply_markup(reply_markup=None)

    await cb.message.answer("Готово. Стратегия сохранена и активирована.")
    
    # Issue first task
    first_day_html = extract_day_html(steps, 1)
    await cb.message.answer(first_day_html or "Сегодняшний шаг недоступен.", reply_markup=kb_daily_step())

    await state.update_data(draft_strategy_text=None, draft_steps=None)


@router.callback_query(F.data == "review:edit")
async def review_edit(cb: CallbackQuery, state: FSMContext):
    """
    Start strategy editing process.
    """
    await cb.answer()
    await state.set_state(ReviewFSM.await_feedback)
    with contextlib.suppress(Exception):
        await cb.message.edit_reply_markup(reply_markup=None)
    await cb.message.answer(
        "Ок. Опиши коротко голосом или текстом, что меняем. Например: "
        "«без соцсетей, больше офлайн-каналов; добавить партнёрства с фитнес-клубами». Отправь сообщение."
    )


@router.message(ReviewFSM.await_feedback, F.text)
async def review_feedback_text(message: Message, state: FSMContext):
    """
    Handle text feedback for strategy revision.
    """
    feedback = (message.text or "").strip()
    if not feedback or len(feedback) < 3:
        await message.answer("Слишком коротко. Напиши конкретнее или отправь голосовым сообщением.")
        return

    data = await state.get_data()
    edit_mode = data.get("edit_mode")

    stop_typing = asyncio.Event()
    typing_task = asyncio.create_task(typing_loop(message.bot, message.chat.id, stop_typing))

    try:
        if edit_mode == "active_strategy":
            await _handle_active_strategy_edit(message, state, data, feedback)
        else:
            await _handle_initial_review_edit(message, state, data, feedback)
    except Exception as e:
        logger.exception("Error processing feedback: %s", e)
        await message.answer("Не удалось переработать стратегию. Сформулируй правки конкретнее и отправь ещё раз.")
    finally:
        stop_typing.set()
        with contextlib.suppress(Exception):
            await typing_task


@router.message(ReviewFSM.await_feedback, F.voice | F.audio | F.video_note)
async def review_feedback_voice(message: Message, state: FSMContext):
    """
    Handle voice/audio feedback for strategy revision.
    """
    await message.answer("Ок, распознаю голос и учту правки…")

    stop_typing = asyncio.Event()
    typing_task = asyncio.create_task(typing_loop(message.bot, message.chat.id, stop_typing, ChatAction.TYPING))

    try:
        # Get audio info and download
        file_id, filename = get_audio_info(message)
        audio_bytes = await download_file_bytes(message, file_id)
        
        # Transcribe audio
        feedback = await transcribe_bytes_openai(audio_bytes, filename)
        
        if not feedback or len(feedback.strip()) < 3:
            await message.answer("Слишком коротко. Скажи конкретнее, что поменять.")
            return

        data = await state.get_data()
        edit_mode = data.get("edit_mode")

        if edit_mode == "active_strategy":
            await _handle_active_strategy_edit(message, state, data, feedback)
        else:
            await _handle_initial_review_edit(message, state, data, feedback)
            
    except Exception as e:
        logger.exception("Error processing voice feedback: %s", e)
        await message.answer("Что-то пошло не так с обработкой голосовых правок. Отправь ещё раз или напиши текстом 🙏")
    finally:
        stop_typing.set()
        with contextlib.suppress(Exception):
            await typing_task


async def _handle_active_strategy_edit(
    message: Message, 
    state: FSMContext, 
    data: Dict[str, Any], 
    feedback: str
) -> None:
    """Handle editing of active strategy."""
    survey = data.get("edit_user_survey") or {}
    prev_strategy = data.get("edit_prev_strategy") or ""

    await message.answer("Перерабатываю стратегию с учётом твоих правок…")
    
    strategy_service = StrategyService()
    sanitizer = StepsSanitizer()
    
    new_strategy, new_steps = await strategy_service.rebuild_strategy_and_steps_with_feedback(
        survey, prev_strategy, feedback
    )
    new_steps = sanitizer.sanitize_steps(new_steps, survey)
    
    clean_strategy = strategy_without_day_blocks(new_strategy)

    await state.update_data(
        edit_preview_strategy=clean_strategy,
        edit_preview_steps=new_steps,
    )

    await message.answer(clean_strategy or "Стратегия пустая.")
    await message.answer("Перезаписать текущую стратегию этой версией?", reply_markup=kb_strategy_overwrite_confirm())


async def _handle_initial_review_edit(
    message: Message, 
    state: FSMContext, 
    data: Dict[str, Any], 
    feedback: str
) -> None:
    """Handle editing of initial strategy review."""
    survey_payload = data.get("survey_payload") or {}
    prev_strategy = data.get("draft_strategy_text") or ""

    await message.answer("Ок, перерабатываю с учётом правок…")
    
    strategy_service = StrategyService()
    sanitizer = StepsSanitizer()
    
    new_strategy, new_steps = await strategy_service.rebuild_strategy_and_steps_with_feedback(
        survey_payload, prev_strategy, feedback
    )
    new_steps = sanitizer.sanitize_steps(new_steps, survey_payload)
    
    await state.update_data(draft_strategy_text=new_strategy, draft_steps=new_steps)

    clean_strategy = strategy_without_day_blocks(new_strategy)
    await message.answer(clean_strategy or "Стратегия пустая.", reply_markup=kb_review())
    # Exit feedback state to avoid looping on further user messages
    with contextlib.suppress(Exception):
        await state.set_state(None)


# kb_review is imported from src.bot.keyboards.survey
