import logging
import asyncio
from aiogram import Router, F
from aiogram.types import CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton
from aiogram.fsm.context import FSMContext
from aiogram.exceptions import TelegramBadRequest
from db import get_user_language, get_language_text, get_user_balance, DATA_DB, MENU_DB
from db_pool import data_pool, menu_pool, execute_with_retry, execute_write

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

TAG_CB_PREFIX = "tag:"
DISTRICT_CB_PREFIX = "dist:"
DELIVERY_CB_PREFIX = "del:"
DELIVERY_INFO_CB_PREFIX = "di:"
BACK_TO_PRODUCT_PREFIX = "btp:"

def check_callback_length(callback_data: str) -> bool:
    """Проверяет, что callback_data не превышает 64 байта"""
    byte_length = len(callback_data.encode('utf-8'))
    if byte_length > 64:
        logger.warning(f"⚠️ callback_data слишком длинный: {byte_length} байт > 64")
        logger.warning(f"Данные: {callback_data}")
        return False
    return True

def safe_callback_data(base: str, *parts) -> str:
    """Создает callback_data, гарантированно не превышающий 64 байта"""
    # Фильтруем пустые и None значения
    clean_parts = [str(p).strip() for p in parts if p is not None and str(p).strip()]
    
    callback = f"{base}:{':'.join(clean_parts)}"
    
    # Проверяем длину
    if len(callback.encode('utf-8')) > 64:
        logger.warning(f"Сокращаем callback_data: {callback}")
        
        # Сокращаем самые длинные части
        shortened_parts = []
        for part in clean_parts:
            part_str = str(part)
            # Если часть длинная - сокращаем
            if len(part_str) > 15:
                shortened_parts.append(part_str[:12])
            else:
                shortened_parts.append(part_str)
        
        callback = f"{base}:{':'.join(shortened_parts)}"
        
        # Если все еще слишком длинный, оставляем только ID
        if len(callback.encode('utf-8')) > 64:
            callback = f"{base}:{':'.join(shortened_parts[:3])}"
    
    if not check_callback_length(callback):
        logger.error(f"Не удалось сократить callback_data: {callback}")
        # В крайнем случае возвращаем минимальную версию
        callback = f"{base}:{clean_parts[0]}" if clean_parts else base
    
    logger.info(f"Generated callback_data: {callback}")
    return callback

async def get_button9_text(lang: str) -> str:
    label = "⬅️ Назад"
    try:
        query = "SELECT button9 FROM language WHERE name = ?"
        result = await execute_with_retry(menu_pool, query, (lang,))
        if result and result[0]['button9'] and str(result[0]['button9']).strip():
            label = str(result[0]['button9']).strip()
    except Exception as e:
        logger.error(f"get_button9_text error for lang={lang}: {e}")
    return label

async def get_button11_text(lang: str) -> str:
    label = "🚗 Доставка"
    try:
        query = "SELECT button11 FROM language WHERE name = ?"
        result = await execute_with_retry(menu_pool, query, (lang,))
        if result and result[0]['button11'] and str(result[0]['button11']).strip():
            label = str(result[0]['button11']).strip()
    except Exception as e:
        logger.error(f"get_button11_text error for lang={lang}: {e}")
    return label

async def get_city_delivery_status(city_id: int) -> bool:
    """Проверяет доступна ли доставка для города"""
    try:
        query = "SELECT delivery FROM city WHERE city_id = ?"
        result = await execute_with_retry(data_pool, query, (city_id,))
        if result and result[0]['delivery']:
            delivery_status = str(result[0]['delivery']).strip().lower()
            return delivery_status == 'yes'
        return False
    except Exception as e:
        logger.error(f"get_city_delivery_status error for city_id={city_id}: {e}")
        return False

async def get_city_delivery_options(city_id: int) -> list[tuple[str, str]]:
    """Получает опции доставки для указанного города"""
    try:
        # АСИНХРОННО проверяем существование таблицы
        check_query = "SELECT name FROM sqlite_master WHERE type='table' AND name='delivery'"
        table_exists = await execute_with_retry(data_pool, check_query)
        
        if not table_exists:
            return []
        
        # Получаем все записи из таблицы delivery
        query = "SELECT city_id, name, text FROM delivery"
        result = await execute_with_retry(data_pool, query)
        
        options = []
        for row in result:
            if row['city_id'] and row['name'] and row['text']:
                delivery_city_ids = str(row['city_id']).strip().split(',')
                if str(city_id) in delivery_city_ids:
                    name = str(row['name']).strip()
                    text = str(row['text']).strip()
                    if name and text:
                        options.append((name, text))
        
        logger.info(f"Found {len(options)} delivery options for city {city_id}")
        return options
        
    except Exception as e:
        logger.error(f"get_city_delivery_options error for city_id={city_id}: {e}")
        return []

async def get_city_districts(city_id: int, product_id: int, tag_index: int) -> list[str]:
    """Получает список районов для города из нового формата: city_id:district1-district2;city_id2:district3-district4"""
    try:
        tag_column = f"product_tags{tag_index}"
        
        # АСИНХРОННО проверяем существование колонки
        pragma_query = "PRAGMA table_info(products)"
        columns_info = await execute_with_retry(data_pool, pragma_query)
        existing_columns = [col['name'] for col in columns_info]
        
        if tag_column not in existing_columns:
            return []
        
        # Получаем данные тега
        query = f"SELECT {tag_column} FROM products WHERE product_id = ?"
        result = await execute_with_retry(data_pool, query, (product_id,))
        
        if not result or not result[0][tag_column]:
            return []
        
        tag_data = str(result[0][tag_column]).strip()
        if not tag_data:
            return []
        
        parts = tag_data.split(',')
        if len(parts) >= 3:
            districts_data = parts[2].strip()
            if districts_data:
                districts = parse_districts_with_city_ids(districts_data, city_id)
                return districts
        return []
        
    except Exception as e:
        logger.error(f"get_city_districts error for city_id={city_id}, product_id={product_id}, tag_index={tag_index}: {e}")
        return []

def parse_districts_with_city_ids(districts_data: str, target_city_id: int) -> list[str]:
    """Парсит новый формат районов с ID городов и возвращает районы для указанного города"""
    try:
        districts = []
        
        city_groups = districts_data.split(';')
        
        for group in city_groups:
            group = group.strip()
            if not group:
                continue
                
            if ':' in group:
                city_id_str, city_districts = group.split(':', 1)
                
                if city_id_str.strip() == str(target_city_id):
                    city_districts_list = [d.strip() for d in city_districts.split('-') if d.strip()]
                    districts.extend(city_districts_list)
        
        return districts
        
    except Exception as e:
        logger.error(f"parse_districts_with_city_ids error for districts_data={districts_data}, target_city_id={target_city_id}: {e}")
        return []

async def get_product_tags(product_id: int, city_id: int) -> list[tuple[str, float, str, int]]:
    """Получает теги товара с ценами в валюте города и сортирует по цене (от меньшей к большей)"""
    tags = []
    try:
        from handlers.catalog import get_city_currency
        currency_info = await get_city_currency(city_id)
        if not currency_info:
            return tags
        
        currency, exchange_rate = currency_info
        
        # АСИНХРОННО проверяем существование колонок
        pragma_query = "PRAGMA table_info(products)"
        columns_info = await execute_with_retry(data_pool, pragma_query)
        existing_columns = [col['name'] for col in columns_info]
        
        for i in range(1, 51):
            tag_col = f"product_tags{i}"
            if tag_col in existing_columns:
                query = f"SELECT {tag_col} FROM products WHERE product_id = ?"
                result = await execute_with_retry(data_pool, query, (product_id,))
                
                if result and result[0][tag_col]:
                    tag_data = str(result[0][tag_col]).strip()
                    if tag_data:
                        parts = [p.strip() for p in tag_data.split(',')]
                        if len(parts) >= 2:
                            tag_name = parts[0]
                            try:
                                base_price = float(parts[1])
                                final_price = base_price * exchange_rate
                                tags.append((tag_name, final_price, currency, i))
                            except ValueError:
                                continue
        
        tags.sort(key=lambda x: x[1])
        
        return tags
        
    except Exception as e:
        logger.error(f"get_product_tags error product_id={product_id}, city_id={city_id}: {e}")
        return []

async def build_product_tags_keyboard(lang: str, tags: list[tuple[str, float, str, int]], product_id: int, city_id: int) -> InlineKeyboardMarkup:
    """Строит клавиатуру с тегами товара ОТСОРТИРОВАННЫМИ ПО ЦЕНЕ"""
    rows: list[list[InlineKeyboardButton]] = []
    
    for tag_name, price, currency, tag_index in tags:
        if price.is_integer():
            price_str = f"{int(price)}"
        else:
            price_str = f"{price:.2f}"
        
        button_text = f"{tag_name} - {price_str} {currency}"
        
        # СОКРАЩАЕМ callback_data
        callback_data = safe_callback_data(TAG_CB_PREFIX, product_id, city_id, tag_index, tag_name)
        rows.append([InlineKeyboardButton(
            text=button_text,
            callback_data=callback_data
        )])
    
    back_to_product_cb = safe_callback_data(BACK_TO_PRODUCT_PREFIX, product_id, city_id)
    rows.append([InlineKeyboardButton(text=await get_button9_text(lang), callback_data=back_to_product_cb)])
    
    return InlineKeyboardMarkup(inline_keyboard=rows)

async def build_districts_keyboard(lang: str, districts: list[str], product_id: int, city_id: int, tag_index: int, tag_name: str) -> InlineKeyboardMarkup:
    """Строит клавиатуру с районами города (заменяет ~ на пробелы в отображаемых названиях)"""
    rows: list[list[InlineKeyboardButton]] = []
    
    delivery_available = await get_city_delivery_status(city_id)
    if delivery_available:
        button11_text = await get_button11_text(lang)
        callback_data = safe_callback_data(DELIVERY_CB_PREFIX, product_id, city_id, tag_index)
        rows.append([InlineKeyboardButton(
            text=button11_text,
            callback_data=callback_data
        )])
    
    for district in districts:
        # Заменяем ~ на пробелы в отображаемом тексте кнопки
        display_district = district.replace('~', ' ')
        
        # СОКРАЩАЕМ callback_data для районов (оригинальное название с ~ остается в callback)
        callback_data = safe_callback_data(DISTRICT_CB_PREFIX, product_id, city_id, tag_index, district)
        rows.append([InlineKeyboardButton(
            text=display_district,
            callback_data=callback_data
        )])
    
    back_to_product_cb = safe_callback_data(BACK_TO_PRODUCT_PREFIX, product_id, city_id)
    rows.append([InlineKeyboardButton(text=await get_button9_text(lang), callback_data=back_to_product_cb)])
    
    return InlineKeyboardMarkup(inline_keyboard=rows)

async def build_delivery_info_keyboard(lang: str, product_id: int, city_id: int, tag_index: int) -> InlineKeyboardMarkup:
    """Строит клавиатуру с опциями доставки"""
    rows: list[list[InlineKeyboardButton]] = []
    
    delivery_options = await get_city_delivery_options(city_id)
    
    if not delivery_options:
        # Если нет опций доставки, показываем только кнопку назад
        back_to_product_cb = safe_callback_data(BACK_TO_PRODUCT_PREFIX, product_id, city_id)
        return InlineKeyboardMarkup(
            inline_keyboard=[[
                InlineKeyboardButton(text=await get_button9_text(lang), callback_data=back_to_product_cb)
            ]]
        )
    
    for option_name, option_text in delivery_options:
        # СОКРАЩАЕМ callback_data
        callback_data = safe_callback_data(DELIVERY_INFO_CB_PREFIX, product_id, city_id, tag_index, option_name)
        rows.append([InlineKeyboardButton(
            text=option_name,
            callback_data=callback_data
        )])
    
    back_to_product_cb = safe_callback_data(BACK_TO_PRODUCT_PREFIX, product_id, city_id)
    rows.append([InlineKeyboardButton(text=await get_button9_text(lang), callback_data=back_to_product_cb)])
    
    return InlineKeyboardMarkup(inline_keyboard=rows)

@router.callback_query(F.data.startswith(TAG_CB_PREFIX))
async def on_tag_clicked(cb: CallbackQuery):
    """Обработчик выбора тега товара - показывает районы"""
    user_id = cb.from_user.id
    lang = await get_user_language(user_id)
    
    try:
        # ✅ СРАЗУ отвечаем Telegram
        await cb.answer()
        
        payload = cb.data[len(TAG_CB_PREFIX):]
        logger.info(f"Tag callback payload: {payload}")
        
        # Очищаем и парсим части
        parts = [p.strip() for p in payload.split(":") if p.strip()]
        
        if len(parts) >= 3:
            product_id = int(parts[0])
            city_id = int(parts[1])
            tag_index = int(parts[2])
            # tag_name не обязателен здесь
        else:
            raise ValueError(f"Недостаточно частей в callback_data: {len(parts)}")
            
    except Exception as e:
        logger.error(f"Error parsing tag callback: {e}, data: {cb.data}")
        await cb.answer("Ошибка выбора варианта", show_alert=True)
        return
    
    try:
        await cb.message.delete()
    except Exception as e:
        logger.warning(f"Failed to delete message: {e}")
    
    text7_content = await get_language_text(lang, "text7") or "Выберите район доставки:"
    
    districts = await get_city_districts(city_id, product_id, tag_index)
    
    if not districts:
        error_text = "Товар закончился,выберите другую граммовку."
        back_to_product_cb = safe_callback_data(BACK_TO_PRODUCT_PREFIX, product_id, city_id)
        kb = InlineKeyboardMarkup(
            inline_keyboard=[[
                InlineKeyboardButton(text=await get_button9_text(lang), callback_data=back_to_product_cb)
            ]]
        )
        await cb.message.answer(error_text, reply_markup=kb)
        return
    
    # Получаем полное название тега из базы
    tags = await get_product_tags(product_id, city_id)
    tag_name = None
    for tag in tags:
        if tag[3] == tag_index:
            tag_name = tag[0]
            break
    
    if not tag_name:
        await cb.answer("Вариант не найден", show_alert=True)
        return
    
    kb = await build_districts_keyboard(lang, districts, product_id, city_id, tag_index, tag_name)
    
    await cb.message.answer(text7_content, reply_markup=kb)

@router.callback_query(F.data.startswith(DELIVERY_CB_PREFIX))
async def on_delivery_clicked(cb: CallbackQuery):
    """Обработчик выбора доставки - показывает опции доставки ДЛЯ ВЫБРАННОГО ГОРОДА"""
    user_id = cb.from_user.id
    lang = await get_user_language(user_id)
    
    try:
        # ✅ СРАЗУ отвечаем Telegram
        await cb.answer()
        
        payload = cb.data[len(DELIVERY_CB_PREFIX):]
        logger.info(f"Delivery callback payload: {payload}")
        
        # Очищаем и парсим части
        parts = [p.strip() for p in payload.split(":") if p.strip()]
        
        if len(parts) >= 3:
            product_id = int(parts[0])
            city_id = int(parts[1])
            tag_index = int(parts[2])
        else:
            raise ValueError(f"Недостаточно частей в callback_data: {len(parts)}")
            
    except Exception as e:
        logger.error(f"Error parsing delivery callback: {e}, data: {cb.data}")
        await cb.answer("Ошибка выбора доставки", show_alert=True)
        return
    
    try:
        await cb.message.delete()
    except Exception as e:
        logger.warning(f"Failed to delete message: {e}")
    
    text33_content = await get_language_text(lang, "text33") or "Выберите способ доставки:"
    
    kb = await build_delivery_info_keyboard(lang, product_id, city_id, tag_index)
    
    await cb.message.answer(text33_content, reply_markup=kb)

@router.callback_query(F.data.startswith(DELIVERY_INFO_CB_PREFIX))
async def on_delivery_info_clicked(cb: CallbackQuery):
    """Обработчик выбора опции доставки - показывает текст доставки в сообщении"""
    user_id = cb.from_user.id
    lang = await get_user_language(user_id)
    
    try:
        # ✅ СРАЗУ отвечаем Telegram
        await cb.answer()
        
        payload = cb.data[len(DELIVERY_INFO_CB_PREFIX):]
        logger.info(f"Delivery info callback payload: {payload}")
        
        # Очищаем и парсим части
        parts = [p.strip() for p in payload.split(":") if p.strip()]
        
        if len(parts) >= 4:
            product_id = int(parts[0])
            city_id = int(parts[1])
            tag_index = int(parts[2])
            option_name = parts[3]
        else:
            raise ValueError(f"Недостаточно частей в callback_data: {len(parts)}")
            
    except Exception as e:
        logger.error(f"Error parsing delivery info callback: {e}, data: {cb.data}")
        await cb.answer("Ошибка выбора опции доставки", show_alert=True)
        return
    
    try:
        await cb.message.delete()
    except Exception as e:
        logger.warning(f"Failed to delete message: {e}")
    
    delivery_options = await get_city_delivery_options(city_id)
    option_text = ""
    
    # Ищем полное название опции доставки
    for name, text in delivery_options:
        if name == option_name or name.startswith(option_name):
            option_text = text
            break
    
    if not option_text:
        option_text = "Информация о доставке не найдена"
    
    back_to_delivery_cb = safe_callback_data(DELIVERY_CB_PREFIX, product_id, city_id, tag_index)
    kb = InlineKeyboardMarkup(
        inline_keyboard=[[
            InlineKeyboardButton(text=await get_button9_text(lang), callback_data=back_to_delivery_cb)
        ]]
    )
    
    await cb.message.answer(option_text, reply_markup=kb)

@router.callback_query(F.data.startswith(DISTRICT_CB_PREFIX))
async def on_district_clicked(cb: CallbackQuery):
    """Обработчик выбора района - показывает опции оплаты"""
    user_id = cb.from_user.id
    lang = await get_user_language(user_id)
    
    try:
        # ✅ СРАЗУ отвечаем Telegram
        await cb.answer()
        
        payload = cb.data[len(DISTRICT_CB_PREFIX):]
        logger.info(f"District callback payload: {payload}")
        
        # Очищаем и парсим части
        parts = [p.strip() for p in payload.split(":") if p.strip()]
        
        if len(parts) >= 4:
            product_id = int(parts[0])
            city_id = int(parts[1])
            tag_index = int(parts[2])
            district_name = parts[3]
        else:
            raise ValueError(f"Недостаточно частей в callback_data: {len(parts)}")
            
    except Exception as e:
        logger.error(f"Error parsing district callback: {e}, data: {cb.data}")
        await cb.answer("Ошибка выбора района", show_alert=True)
        return
    
    # Получаем tag_name из базы
    tags = await get_product_tags(product_id, city_id)
    tag_name = None
    for tag in tags:
        if tag[3] == tag_index:
            tag_name = tag[0]
            break
    
    if not tag_name:
        await cb.answer("Вариант не найден", show_alert=True)
        return
    
    try:
        await cb.message.delete()
    except Exception as e:
        logger.warning(f"Failed to delete message: {e}")
    
    text10_content = await get_language_text(lang, "text10") or "Выберите способ оплаты:"
    
    from handlers.payment_handlers import build_payment_keyboard
    kb = await build_payment_keyboard(lang, product_id, city_id, tag_index, tag_name, district_name, user_id)
    
    await cb.message.answer(text10_content, reply_markup=kb)

@router.callback_query(F.data.startswith(BACK_TO_PRODUCT_PREFIX))
async def on_back_to_product_from_handlers(cb: CallbackQuery):
    """Обработчик возврата к карточке товара из product_handlers"""
    user_id = cb.from_user.id
    lang = await get_user_language(user_id)
    
    try:
        # ✅ СРАЗУ отвечаем Telegram
        await cb.answer()
        
        payload = cb.data[len(BACK_TO_PRODUCT_PREFIX):]
        parts = [p.strip() for p in payload.split(":") if p.strip()]
        
        if len(parts) >= 2:
            product_id = int(parts[0])
            city_id = int(parts[1])
        else:
            raise ValueError(f"Недостаточно частей в callback_data: {len(parts)}")
            
    except Exception as e:
        logger.error(f"Error parsing back to product callback: {e}")
        await cb.answer("Ошибка возврата", show_alert=True)
        return
    
    try:
        await cb.message.delete()
    except Exception as e:
        logger.warning(f"Failed to delete message: {e}")
    
    from handlers.catalog import get_product_details, get_city_name, get_product_tags, build_product_tags_keyboard, resolve_image_path
    from aiogram.types.input_file import FSInputFile
    
    product = await get_product_details(product_id)
    city_name = await get_city_name(city_id)
    
    if not product:
        await cb.answer("Товар не найден", show_alert=True)
        return
    
    city_line = f"🏙️ Город: {city_name or 'Не указан'}"
    name_line = f"📦 Товар: {product.get('product_name', 'Без названия')}"
    
    description = product.get('product_description', '')
    desc_line = f"📝 {description}" if description else ""
    
    text6_content = await get_language_text(lang, "text6") or ""
    text6_line = f"\n{text6_content}" if text6_content else ""
    
    message_parts = [city_line, name_line]
    if desc_line:
        message_parts.append(desc_line)
    if text6_line:
        message_parts.append(text6_line)
    
    caption_text = "\n".join(message_parts)
    
    tags = await get_product_tags(product_id, city_id)
    kb = await build_product_tags_keyboard(lang, tags, product_id, city_id)
    
    image_path = product.get('product_image', '')
    if image_path:
        is_url, resolved_path = resolve_image_path(image_path)
        if resolved_path:
            try:
                if is_url:
                    await cb.message.answer_photo(
                        photo=resolved_path, 
                        caption=caption_text, 
                        reply_markup=kb
                    )
                else:
                    await cb.message.answer_photo(
                        photo=FSInputFile(resolved_path), 
                        caption=caption_text, 
                        reply_markup=kb
                    )
                return
            except Exception as e:
                logger.error(f"Failed to send photo: {e}")
    
    await cb.message.answer(caption_text, reply_markup=kb)