# ======= VAT OPERATIONS API MODULE =======
# Module for importing VAT Account operations from E-Taxes Azerbaijan
# and creating Journal Entries in ERPNext

import frappe
import requests
import json
from datetime import datetime
from frappe.utils import now_datetime, getdate
from invoice_az.auth import record_etaxes_activity, get_default_asan_login

# API Endpoint
VAT_OPERATIONS_URL = "https://new.e-taxes.gov.az/api/po/vatacc/public/v1/operation/find.outbox"

DEFAULT_HEADERS = {
    "Accept": "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "Cache-Control": "no-cache"
}

# Маппинг типов операций из API в азербайджанские названия
OPERATION_TYPE_MAPPING = {
    'SUB_TO_SUB': 'Sub uçot hesabı → Sub uçot hesabı',
    'UNKNOWN_TO_OTHER_SUB': 'Naməlum → digər Sub hesab',
    'CURRENT_TO_SUB': 'Cari → Sub uçot hesabı',
    'CURRENT_TO_UNKNOWN': 'Cari → Naməlum',
    'SUB_TO_IMPORT': 'Sub uçot hesabı → İdxal',
    'UNKNOWN_TO_IMPORT': 'Naməlum → İdxal',
    'SUB_TO_BUDGET': 'Sub uçot hesabı → Büdcə',
    'UNKNOWN_TO_BUDGET': 'Naməlum → Büdcə',
    'AUTO': 'Sub uçot hesabı → Büdcə'  # AUTO операции трактуются как SUB_TO_BUDGET
}


def map_operation_type(api_operation_type):
    """
    Конвертирует тип операции из API в азербайджанское название.

    Args:
        api_operation_type (str): Тип операции из API (например, SUB_TO_SUB)

    Returns:
        str: Азербайджанское название (например, Sub uçot hesabı → Sub uçot hesabı)
    """
    return OPERATION_TYPE_MAPPING.get(api_operation_type, api_operation_type)


def parse_operation_date(operation_date_str):
    """
    Парсит дату из формата e-taxes "20250319154646" в datetime.date

    Args:
        operation_date_str (str): Дата в формате "YYYYMMDDHHMMSS"

    Returns:
        datetime.date: Объект даты или None при ошибке
    """
    try:
        if not operation_date_str or len(operation_date_str) < 8:
            frappe.log_error(f"Invalid operation date format: {operation_date_str}", "VAT Date Parse Error")
            return None

        # Формат: YYYYMMDDHHMMSS
        year = int(operation_date_str[0:4])
        month = int(operation_date_str[4:6])
        day = int(operation_date_str[6:8])

        return datetime(year, month, day).date()
    except Exception as e:
        frappe.log_error(f"Error parsing operation date '{operation_date_str}': {str(e)}", "VAT Date Parse Error")
        return None


@frappe.whitelist()
def get_vat_operations(token, date_from, date_to, max_count=50, offset=0):
    """
    Получение списка VAT Account операций из e-taxes

    Args:
        token (str): Bearer токен для авторизации
        date_from (str): Дата начала в формате "YYYY-MM-DD"
        date_to (str): Дата окончания в формате "YYYY-MM-DD"
        max_count (int): Максимальное количество записей (по умолчанию 50)
        offset (int): Смещение для пагинации (по умолчанию 0)

    Returns:
        dict: Словарь с результатами или ошибкой
    """
    record_etaxes_activity()

    try:
        max_count = int(max_count)
        offset = int(offset)
    except (ValueError, TypeError):
        max_count = 50
        offset = 0

    payload = {
        "accounts": None,
        "creationDateFrom": date_from,
        "creationDateTo": date_to,
        "maxCount": max_count,
        "offset": offset,
        "sortAsc": True,
        "sortBy": "DATE",
        "taxCodes": None
    }

    headers = DEFAULT_HEADERS.copy()
    headers["x-authorization"] = f"Bearer {token}"

    try:
        response = requests.post(VAT_OPERATIONS_URL, json=payload, headers=headers)

        # Handle 500 error
        if response.status_code == 500:
            frappe.log_error(f"[VAT_API] Server error 500", "E-Taxes Server Error")
            return {
                "error": "server_error",
                "message": "Service temporarily unavailable. Please try again in a few minutes.",
                "status_code": 500
            }

        # Handle 401 error - refresh token
        if response.status_code == 401:
            frappe.log_error(f"[VAT_API] Unauthorized 401 - token expired", "E-Taxes Auth Error")

            asan_login_settings = get_default_asan_login()
            if asan_login_settings.get('found'):
                fresh_token = asan_login_settings['main_token']
                headers["x-authorization"] = f"Bearer {fresh_token}"

                frappe.log_error(f"[VAT_API] Retrying with fresh token", "E-Taxes Auth Retry")

                response = requests.post(VAT_OPERATIONS_URL, json=payload, headers=headers)

                if response.status_code == 401:
                    frappe.log_error(f"[VAT_API] Still unauthorized after token refresh", "E-Taxes Auth Failed")
                    return {
                        "error": "unauthorized",
                        "message": "Authentication required. Please login again."
                    }
            else:
                frappe.log_error(f"[VAT_API] No Asan Login settings found", "E-Taxes Auth Error")
                return {
                    "error": "unauthorized",
                    "message": "Authentication required. Please login again."
                }

        response.raise_for_status()

        # Получаем результат
        result = response.json()

        # Преобразуем типы операций в азербайджанские названия
        if 'operations' in result and isinstance(result['operations'], list):
            operations = result['operations']

            for op in operations:
                # Преобразуем тип операции в красивое азербайджанское название
                if 'operationType' in op:
                    op['operationType'] = map_operation_type(op['operationType'])

            frappe.logger().info(f"VAT Operations loaded: {len(operations)} operations")

        return result

    except requests.exceptions.HTTPError as e:
        frappe.log_error(f"[VAT_API] HTTP error: {e.response.status_code} - {str(e)}", "E-Taxes HTTP Error")

        if e.response.status_code == 401:
            return {
                "error": "unauthorized",
                "message": "Authentication required. Please login again."
            }
        elif e.response.status_code == 500:
            return {
                "error": "server_error",
                "message": "Service temporarily unavailable. Please try again in a few minutes.",
                "status_code": 500
            }

        return {"error": "http_error", "message": "An unknown error occurred, please try again."}
    except Exception as e:
        frappe.log_error(f"[VAT_API] Unexpected error: {str(e)}\n{frappe.get_traceback()}", "E-Taxes Error")
        return {"error": "unknown_error", "message": "An unknown error occurred, please try again."}


def normalize_customer_name(name):
    """
    Нормализует имя клиента для поиска
    Использует normalize_string() из sales_api.py

    Args:
        name (str): Имя клиента

    Returns:
        str: Нормализованное имя
    """
    if not name:
        return ''

    try:
        from invoice_az.sales_api import normalize_string
        return normalize_string(name, consider_azeri=True)
    except Exception as e:
        frappe.log_error(f"Error normalizing customer name '{name}': {str(e)}", "VAT Customer Normalize Error")
        # Fallback to simple lowercase if normalize_string fails
        return name.lower().strip()


def find_customer_by_tin(tin):
    """
    Поиск клиента по TIN (напрямую в Customer.tax_id)
    БУДУЩЕЕ: Переключение на customer_mappings

    Args:
        tin (str): TIN клиента

    Returns:
        str: Имя клиента или None
    """
    if not tin:
        return None

    try:
        # ТЕКУЩАЯ РЕАЛИЗАЦИЯ: Прямой поиск по tax_id
        customer_name = frappe.db.get_value('Customer', {'tax_id': tin}, 'name')

        if customer_name:
            return customer_name

        # БУДУЩЕЕ: Раскомментировать для использования customer_mappings
        # settings = frappe.get_all('E-Taxes Settings',
        #                          filters={'is_active': 1},
        #                          limit=1)
        # if settings:
        #     settings_doc = frappe.get_doc('E-Taxes Settings', settings[0].name)
        #     for mapping in settings_doc.customer_mappings:
        #         if mapping.etaxes_tax_id == tin and mapping.erp_customer:
        #             return mapping.erp_customer

        return None

    except Exception as e:
        frappe.log_error(f"Error finding customer by TIN {tin}: {str(e)}", "VAT Customer Lookup Error")
        return None


def find_or_create_customer_from_vat_operation(tin, name, settings_doc, auto_create=False):
    """
    Найти или создать клиента из VAT операции с автосозданием маппингов

    Логика поиска (ПРАВИЛЬНЫЙ ПРИОРИТЕТ):
    0. Проверка маппингов (НАИВЫСШИЙ ПРИОРИТЕТ) - что указано в маппинге, то и используется
       - Если найден маппинг с заполненным erp_customer → возвращаем его
       - Если найден маппинг с пустым erp_customer → запоминаем и продолжаем поиск
    1. Если auto_create=False → return None
    2. Поиск Customer в базе (только если маппинг пустой или отсутствует):
       - По tax_id
       - По точному имени
       - По нормализованному имени
       - Если найден → создать/обновить маппинг
    3. Создание нового Customer + создание/обновление маппинга

    Args:
        tin (str): TIN клиента
        name (str): Имя клиента из операции
        settings_doc (Document): Объект E-Taxes Settings
        auto_create (bool): Разрешить автосоздание

    Returns:
        str: Имя клиента или None
    """
    if not tin:
        return None

    try:
        # Шаг 0: НАИВЫСШИЙ ПРИОРИТЕТ - Проверка маппингов
        existing_mapping_row = None
        if settings_doc and hasattr(settings_doc, 'customer_mappings'):
            for mapping in settings_doc.customer_mappings:
                if mapping.etaxes_tax_id == tin:
                    if mapping.erp_customer:
                        # Маппинг с заполненным erp_customer - это источник истины!
                        return mapping.erp_customer
                    else:
                        # Маппинг существует, но erp_customer пустой - запоминаем для обновления
                        existing_mapping_row = mapping
                    break

        # Если auto_create=False, завершаем поиск
        if not auto_create:
            return None

        # Шаг 1: Поиск Customer по tax_id в базе
        customer_name = frappe.db.get_value('Customer', {'tax_id': tin}, 'name')
        if customer_name:
            # Найден Customer - создаем/обновляем маппинг
            _create_or_update_etaxes_customer_and_mapping(tin, name, customer_name, settings_doc, existing_mapping_row)
            return customer_name

        # Шаг 2: Поиск Customer по точному имени
        if name:
            customer_name = frappe.db.get_value('Customer', {'customer_name': name}, 'name')
            if customer_name:
                # Обновляем tax_id если нужно (с защитой от конфликта)
                try:
                    customer_doc = frappe.get_doc('Customer', customer_name)
                    if not customer_doc.tax_id or customer_doc.tax_id != tin:
                        # Проверяем нет ли уже другого Customer с таким tax_id
                        existing_customer_with_tin = frappe.db.get_value('Customer', {'tax_id': tin}, 'name')
                        if not existing_customer_with_tin or existing_customer_with_tin == customer_name:
                            customer_doc.tax_id = tin
                            customer_doc.save(ignore_permissions=True)
                            frappe.db.commit()
                except Exception:
                    # Игнорируем ошибки обновления tax_id
                    pass

                # Создаем/обновляем маппинг
                _create_or_update_etaxes_customer_and_mapping(tin, name, customer_name, settings_doc, existing_mapping_row)
                return customer_name

        # Шаг 3: Поиск по нормализованному имени
        if name:
            normalized_search_name = normalize_customer_name(name)
            if normalized_search_name:
                all_customers = frappe.get_all('Customer', fields=['name', 'customer_name'])
                for customer in all_customers:
                    customer_normalized = normalize_customer_name(customer.get('customer_name', ''))
                    if customer_normalized == normalized_search_name:
                        # Обновляем tax_id если нужно (с защитой от конфликта)
                        try:
                            customer_doc = frappe.get_doc('Customer', customer['name'])
                            if not customer_doc.tax_id or customer_doc.tax_id != tin:
                                # Проверяем нет ли уже другого Customer с таким tax_id
                                existing_customer_with_tin = frappe.db.get_value('Customer', {'tax_id': tin}, 'name')
                                if not existing_customer_with_tin or existing_customer_with_tin == customer['name']:
                                    customer_doc.tax_id = tin
                                    customer_doc.save(ignore_permissions=True)
                                    frappe.db.commit()
                        except Exception:
                            # Игнорируем ошибки обновления tax_id
                            pass

                        # Создаем/обновляем маппинг
                        _create_or_update_etaxes_customer_and_mapping(tin, name, customer['name'], settings_doc, existing_mapping_row)
                        return customer['name']

        # Шаг 4: Создание нового Customer
        # Получаем default customer group
        default_customer_group = settings_doc.default_customer_group if settings_doc else None
        if not default_customer_group or not frappe.db.exists('Customer Group', default_customer_group):
            default_customer_group = 'All Customer Groups'

        # Создаем Customer (с защитой от race condition)
        try:
            customer_doc = frappe.new_doc('Customer')
            customer_doc.customer_name = name or f"Customer-{tin}"
            customer_doc.customer_type = 'Company'
            customer_doc.customer_group = default_customer_group
            customer_doc.territory = 'All Territories'
            customer_doc.tax_id = tin

            # Payment terms если есть
            if settings_doc and hasattr(settings_doc, 'default_payment_terms') and settings_doc.default_payment_terms:
                customer_doc.payment_terms = settings_doc.default_payment_terms

            customer_doc.insert(ignore_permissions=True)
            frappe.db.commit()

            # Создаем/обновляем маппинг
            _create_or_update_etaxes_customer_and_mapping(tin, name, customer_doc.name, settings_doc, existing_mapping_row)

            return customer_doc.name

        except frappe.exceptions.DuplicateEntryError:
            # Race condition: кто-то уже создал Customer с таким именем или tax_id
            # Попробуем найти снова по tax_id
            customer_name = frappe.db.get_value('Customer', {'tax_id': tin}, 'name')
            if customer_name:
                _create_or_update_etaxes_customer_and_mapping(tin, name, customer_name, settings_doc, existing_mapping_row)
                return customer_name
            # Если не нашли - возвращаем None
            return None

    except Exception as e:
        frappe.log_error(
            f"Error finding/creating customer for TIN {tin}, name {name}: {str(e)}\n{frappe.get_traceback()}",
            "VAT Customer Auto-Create Error"
        )
        return None


def _create_or_update_etaxes_customer_and_mapping(tin, etaxes_name, erp_customer, settings_doc, existing_mapping_row=None):
    """
    Вспомогательная функция для создания/обновления E-Taxes Customers и маппинга
    Работает ТИХО - без сообщений пользователю

    Args:
        tin (str): TIN клиента
        etaxes_name (str): Имя из e-taxes
        erp_customer (str): Имя Customer в ERP
        settings_doc (Document): Объект E-Taxes Settings
        existing_mapping_row (object): Существующая строка маппинга с пустым erp_customer (если есть)
    """
    # Сначала обновляем маппинг (это главное!)
    try:
        if settings_doc:
            if existing_mapping_row:
                # Используем прямое обновление child table через SQL
                default_customer_group = settings_doc.default_customer_group if settings_doc.default_customer_group else 'All Customer Groups'

                # Обновляем через frappe.db.sql напрямую
                frappe.db.sql("""
                    UPDATE `tabE-Taxes Customer Mappings`
                    SET erp_customer = %s,
                        customer_group = COALESCE(NULLIF(customer_group, ''), %s),
                        territory = COALESCE(NULLIF(territory, ''), 'All Territories'),
                        mapping_type = COALESCE(NULLIF(mapping_type, ''), 'Automatic')
                    WHERE parent = %s
                    AND etaxes_tax_id = %s
                """, (erp_customer, default_customer_group, settings_doc.name, tin))
                frappe.db.commit()
            else:
                # Проверяем, нет ли уже маппинга с таким TIN (на всякий случай)
                mapping_exists = False
                if hasattr(settings_doc, 'customer_mappings'):
                    for mapping in settings_doc.customer_mappings:
                        if mapping.etaxes_tax_id == tin:
                            mapping_exists = True
                            break

                if not mapping_exists:
                    # Создаем новую строку маппинга
                    settings_doc.append('customer_mappings', {
                        'etaxes_customer_name': etaxes_name or f"Customer-{tin}",
                        'etaxes_tax_id': tin,
                        'erp_customer': erp_customer,
                        'customer_group': settings_doc.default_customer_group if settings_doc.default_customer_group else 'All Customer Groups',
                        'territory': 'All Territories',
                        'mapping_type': 'Automatic'
                    })
                    settings_doc.save(ignore_permissions=True)
                    frappe.db.commit()
    except Exception as e:
        # Тихая обработка ошибок маппинга - только в лог
        frappe.log_error(
            f"Error updating mapping for TIN {tin}: {str(e)}\n{frappe.get_traceback()}",
            "VAT Mapping Update Error"
        )

    # Потом пытаемся создать/обновить E-Taxes Customers (если упадет - не страшно)
    try:
        # Проверяем существование по полям, а не по name (autoname может генерировать другой формат!)
        existing = frappe.db.get_value('E-Taxes Customers',
                                       {'etaxes_tax_id': tin},
                                       'name')

        if existing:
            try:
                etaxes_customer_doc = frappe.get_doc('E-Taxes Customers', existing)
                if not etaxes_customer_doc.mapped_customer:
                    etaxes_customer_doc.mapped_customer = erp_customer
                    etaxes_customer_doc.save(ignore_permissions=True)
                    frappe.db.commit()
            except Exception:
                # Игнорируем ошибки при обновлении существующего
                pass
        else:
            try:
                etaxes_customer_doc = frappe.new_doc('E-Taxes Customers')
                etaxes_customer_doc.etaxes_party_name = etaxes_name or f"Customer-{tin}"
                etaxes_customer_doc.etaxes_tax_id = tin
                etaxes_customer_doc.etaxes_party_type = 'Receiver'
                etaxes_customer_doc.status = 'New'
                etaxes_customer_doc.mapped_customer = erp_customer
                etaxes_customer_doc.insert(ignore_permissions=True)
                frappe.db.commit()
            except frappe.exceptions.DuplicateEntryError:
                # Игнорируем ошибку дубликата - кто-то уже создал
                pass
            except Exception:
                # Игнорируем любые другие ошибки создания E-Taxes Customers
                pass
    except Exception:
        # Игнорируем ошибки E-Taxes Customers полностью
        pass


def find_account_by_number(account_number, company):
    """
    Поиск счета по номеру счета

    Args:
        account_number (str): Номер счета (например, "226" или "211")
        company (str): Название компании

    Returns:
        str: Имя счета или None
    """
    if not account_number or not company:
        return None

    try:
        # Поиск по полю account_number
        account_name = frappe.db.get_value('Account',
                                          {'account_number': account_number,
                                           'company': company},
                                          'name')

        if account_name:
            return account_name

        # Дополнительный поиск: счет может содержать номер в начале имени
        # Например: "226 - НДС к возмещению"
        accounts = frappe.get_all('Account',
                                 filters={'company': company},
                                 fields=['name', 'account_name'])

        for account in accounts:
            if account.get('name', '').startswith(account_number + ' '):
                return account['name']
            if account.get('account_name', '').startswith(account_number + ' '):
                return account['name']

        return None

    except Exception as e:
        frappe.log_error(f"Error finding account {account_number}: {str(e)}", "VAT Account Lookup Error")
        return None


def get_accounts_for_operation_type(operation_type, company, expense_income_type, tax_code=None):
    """
    Получить счета дебета и кредита для типа операции из E-Taxes Settings.
    Если маппинг не найден, вернуть (None, None).

    Логика строгого соответствия (БЕЗ fallback):
    - Если передан tax_code - ищем ТОЛЬКО маппинг с operation_type + expense_income_type + этот tax_code
    - Если НЕ передан tax_code - ищем ТОЛЬКО маппинг с operation_type + expense_income_type + пустой classification_code
    - Не нашли точное совпадение - возвращаем (None, None)

    Args:
        operation_type (str): Тип операции (например, Sub uçot hesabı → Sub uçot hesabı, Sub uçot hesabı → Büdcə)
        company (str): Название компании
        expense_income_type (str): Тип операции - 'Expense' или 'Income'
        tax_code (str, optional): Код классификации из taxCodeInfo.code

    Returns:
        tuple: (debit_account, credit_account) или (None, None) если маппинг не найден
    """
    try:
        # Ищем дефолтные E-Taxes Settings
        settings_name = frappe.db.get_value('E-Taxes Settings',
                                            {'is_default': 1, 'is_active': 1},
                                            'name')

        if not settings_name:
            # Если нет дефолтных, берем любые активные
            settings_name = frappe.db.get_value('E-Taxes Settings',
                                                {'is_active': 1},
                                                'name')

        if settings_name and operation_type:
            # СТРОГОЕ СООТВЕТСТВИЕ: ищем в зависимости от наличия tax_code
            if tax_code:
                # Случай А: Есть tax_code - ищем ТОЛЬКО с этим конкретным classification_code
                mapping = frappe.db.get_value('E-Taxes VAT Account Mapping',
                                             {'parent': settings_name,
                                              'parenttype': 'E-Taxes Settings',
                                              'operation_type': operation_type,
                                              'expense_income': expense_income_type,
                                              'classification_code': tax_code},
                                             ['debit_account', 'credit_account'],
                                             as_dict=True)

                if mapping:
                    frappe.logger().info(f"Found mapping with classification_code: {tax_code}, expense/income: {expense_income_type}")
                    return (mapping.get('debit_account'), mapping.get('credit_account'))
                else:
                    # Не нашли - возвращаем None (БЕЗ fallback на пустой classification_code)
                    frappe.logger().info(f"No mapping found for operation_type: {operation_type}, expense/income: {expense_income_type} with classification_code: {tax_code}")
                    return (None, None)
            else:
                # Случай Б: Нет tax_code - ищем ТОЛЬКО с пустым classification_code
                mappings = frappe.get_all('E-Taxes VAT Account Mapping',
                                         filters={
                                             'parent': settings_name,
                                             'parenttype': 'E-Taxes Settings',
                                             'operation_type': operation_type,
                                             'expense_income': expense_income_type
                                         },
                                         fields=['debit_account', 'credit_account', 'classification_code'])

                # Ищем маппинг с пустым classification_code
                for mapping in mappings:
                    if not mapping.get('classification_code'):
                        frappe.logger().info(f"Found default mapping (no classification_code) for expense/income: {expense_income_type}")
                        return (mapping.get('debit_account'), mapping.get('credit_account'))

                # Не нашли маппинг с пустым classification_code
                frappe.logger().info(f"No default mapping found for operation_type: {operation_type}, expense/income: {expense_income_type}")
                return (None, None)

        # Маппинг не найден - возвращаем None, None
        return (None, None)

    except Exception as e:
        frappe.log_error(f"Error getting accounts for operation type {operation_type}: {str(e)}",
                        "VAT Account Mapping Error")
        # В случае ошибки возвращаем None, None
        return (None, None)


def create_journal_entry_from_vat_operation(operation_data, company, create_as_draft=0, auto_create_customers=0):
    """
    Создание Journal Entry из VAT операции

    Args:
        operation_data (dict): Данные операции из API
        company (str): Название компании
        create_as_draft (int): 1 для создания в Draft, 0 для auto-submit
        auto_create_customers (int): 1 для автосоздания клиентов, 0 для отключения

    Returns:
        dict: Результат создания с именем JE или ошибкой
    """
    try:
        # Парсим дату операции
        operation_date_str = operation_data.get('operationDate')
        posting_date = parse_operation_date(operation_date_str)

        if not posting_date:
            return {
                'success': False,
                'message': f'Invalid operation date format: {operation_date_str}'
            }

        # Получаем сумму (income или expense)
        income = operation_data.get('income', 0)
        expense = operation_data.get('expense', 0)

        # Определяем тип операции (Expense/Income) и сумму
        if income and income > 0:
            expense_income_type = 'Income'
            amount = income
        elif expense and expense > 0:
            expense_income_type = 'Expense'
            amount = expense
        else:
            return {
                'success': False,
                'message': 'Invalid amount: both income and expense are empty or zero'
            }

        # Получаем тип операции и tax code
        api_operation_type = operation_data.get('operationType', '')
        operation_type = map_operation_type(api_operation_type)

        # Извлекаем tax code из taxCodeInfo
        tax_code = None
        tax_code_info = operation_data.get('taxCodeInfo')
        if tax_code_info and isinstance(tax_code_info, dict):
            tax_code = tax_code_info.get('code')

        # Ищем счета по маппингу с учетом tax_code (если есть)
        debit_account, credit_account = get_accounts_for_operation_type(
            operation_type, company, expense_income_type, tax_code
        )

        # Проверяем что маппинг найден
        if not debit_account or not credit_account:
            # Формируем понятное сообщение об ошибке
            expense_income_label = expense_income_type.lower()  # "Income" → "income", "Expense" → "expense"
            error_message = f"VAT account mapping not found: operation type '{operation_type}', {expense_income_label}"

            if tax_code:
                error_message += f", classification code '{tax_code}'"

            error_dict = {
                'success': False,
                'message': error_message,
                'error_type': 'mapping_not_found',
                'operation_type': operation_type,
                'expense_income_type': expense_income_type
            }

            if tax_code:
                error_dict['classification_code'] = tax_code

            return error_dict

        # Проверяем типы счетов - нужен ли party
        debit_account_type = frappe.db.get_value('Account', debit_account, 'account_type')
        credit_account_type = frappe.db.get_value('Account', credit_account, 'account_type')

        party_required_types = ('Receivable', 'Payable')
        debit_needs_party = debit_account_type in party_required_types
        credit_needs_party = credit_account_type in party_required_types

        # Получаем TIN и ищем/создаем клиента (если хотя бы один счет требует party)
        tin = operation_data.get('tin', '').strip()
        customer_name_from_operation = operation_data.get('name', '')
        customer = None

        if debit_needs_party or credit_needs_party:
            # Получаем настройки E-Taxes для маппингов
            settings_doc = None
            try:
                settings_name = frappe.db.get_value('E-Taxes Settings',
                                                    {'is_default': 1, 'is_active': 1},
                                                    'name')
                if not settings_name:
                    settings_name = frappe.db.get_value('E-Taxes Settings',
                                                        {'is_active': 1},
                                                        'name')
                if settings_name:
                    settings_doc = frappe.get_doc('E-Taxes Settings', settings_name)
            except Exception as e:
                frappe.logger().warning(f"[VAT] Could not load E-Taxes Settings: {str(e)}")

            # Используем новую функцию для поиска/создания клиента
            customer = find_or_create_customer_from_vat_operation(
                tin=tin,
                name=customer_name_from_operation,
                settings_doc=settings_doc,
                auto_create=bool(auto_create_customers)
            )

            if not customer:
                error_message = f'Customer not found for TIN: {tin}'
                if auto_create_customers:
                    error_message = f'Could not find or create customer for TIN: {tin}'

                return {
                    'success': False,
                    'message': error_message,
                    'error_type': 'customer_creation_failed' if auto_create_customers else 'customer_not_found',
                    'tin': tin
                }

        # Создаем Journal Entry
        je = frappe.new_doc('Journal Entry')
        je.posting_date = posting_date
        je.company = company
        je.voucher_type = 'Journal Entry'
        je.user_remark = f"VAT Operation: {operation_data.get('explanation', '')}"
        je.expense_income_type = expense_income_type
        je.customer_name_etaxes = operation_data.get('name', '')

        # Строка 1: Дебет
        debit_entry = {
            'account': debit_account,
            'debit_in_account_currency': amount,
            'credit_in_account_currency': 0
        }

        # Добавляем party если дебетовый счет Receivable/Payable
        if debit_needs_party and customer:
            debit_entry['party_type'] = 'Customer'
            debit_entry['party'] = customer

        je.append('accounts', debit_entry)

        # Строка 2: Кредит
        credit_entry = {
            'account': credit_account,
            'debit_in_account_currency': 0,
            'credit_in_account_currency': amount
        }

        # Добавляем party если кредитовый счет Receivable/Payable
        if credit_needs_party and customer:
            credit_entry['party_type'] = 'Customer'
            credit_entry['party'] = customer

        je.append('accounts', credit_entry)

        # Сохраняем и submit (если не draft режим)
        je.insert()

        if not create_as_draft:
            je.submit()
        else:
            frappe.logger().info(f"Journal Entry {je.name} created as Draft (not submitted)")

        frappe.db.commit()

        return {
            'success': True,
            'journal_entry': je.name,
            'posting_date': str(posting_date),
            'status': 'Draft' if create_as_draft else 'Submitted'
        }

    except Exception as e:
        error_context = "creating draft" if create_as_draft else "creating and submitting"
        frappe.log_error(f"Error {error_context} JE from VAT operation: {str(e)}\n{frappe.get_traceback()}",
                        "VAT JE Creation Error")
        return {
            'success': False,
            'message': f'Error {error_context} Journal Entry: {str(e)}'
        }


def create_vat_operation_record(operation_data, journal_entry_name=None, status='Imported', error_message=None):
    """
    Создание записи E-Taxes VAT Operations для отслеживания

    Args:
        operation_data (dict): Данные операции из API
        journal_entry_name (str): Имя созданного Journal Entry
        status (str): Статус импорта
        error_message (str): Сообщение об ошибке (если есть)

    Returns:
        dict: Результат создания записи
    """
    try:
        operation_id = operation_data.get('id')

        # Проверяем, не импортирована ли уже эта операция
        existing = frappe.db.get_value('E-Taxes VAT Operations',
                                      {'operation_id': operation_id},
                                      'name')

        if existing:
            return {
                'success': True,
                'message': 'Operation already imported',
                'name': existing,
                'already_exists': True
            }

        # Парсим дату
        operation_date_str = operation_data.get('operationDate')
        operation_date = parse_operation_date(operation_date_str)

        # Создаем новую запись
        vat_op = frappe.new_doc('E-Taxes VAT Operations')
        vat_op.operation_id = operation_id
        vat_op.operation_date = operation_date
        vat_op.tin = operation_data.get('tin')
        vat_op.name_field = operation_data.get('name')
        vat_op.operation_type = map_operation_type(operation_data.get('operationType'))
        vat_op.payment_type = operation_data.get('paymentType')
        vat_op.account = operation_data.get('account')
        vat_op.destination = operation_data.get('destination')
        vat_op.income = operation_data.get('income')
        vat_op.receipt_number = operation_data.get('receiptNumber')
        vat_op.explanation = operation_data.get('explanation')
        vat_op.operator_pin = operation_data.get('operatorPin')
        vat_op.operator_name = operation_data.get('operatorName')

        # Tax code info
        tax_code_info = operation_data.get('taxCodeInfo', {})
        if tax_code_info:
            vat_op.tax_code_info = json.dumps(tax_code_info)

        vat_op.journal_entry = journal_entry_name
        vat_op.status = status
        vat_op.error_message = error_message

        vat_op.insert()
        frappe.db.commit()

        return {
            'success': True,
            'name': vat_op.name
        }

    except Exception as e:
        frappe.log_error(f"Error creating VAT operation record: {str(e)}\n{frappe.get_traceback()}",
                        "VAT Record Creation Error")
        return {
            'success': False,
            'message': f'Error creating tracking record: {str(e)}'
        }


@frappe.whitelist()
def import_vat_operations(operations_data, company=None, create_as_draft=0, auto_create_customers=0):
    """
    Импорт VAT операций и создание Journal Entries

    Args:
        operations_data (str/list): JSON строка или список операций
        company (str): Название компании (опционально)
        create_as_draft (int): 1 для создания в Draft, 0 для auto-submit
        auto_create_customers (int): 1 для автосоздания клиентов, 0 для отключения

    Returns:
        dict: Результат импорта с статистикой
    """
    record_etaxes_activity()

    try:
        # Десериализация если нужно
        if isinstance(operations_data, str):
            operations_data = json.loads(operations_data)

        # Обработка create_as_draft параметра
        try:
            create_as_draft = int(create_as_draft)
        except (ValueError, TypeError):
            create_as_draft = 0

        # Обработка auto_create_customers параметра
        try:
            auto_create_customers = int(auto_create_customers)
        except (ValueError, TypeError):
            auto_create_customers = 0

        # Получаем компанию
        if not company:
            company = frappe.defaults.get_user_default('Company')

        if not company:
            return {
                'success': False,
                'message': 'Company not specified'
            }

        # Статистика
        total_count = len(operations_data)
        success_count = 0
        failed_count = 0
        skipped_count = 0
        errors = []

        for operation in operations_data:
            operation_id = operation.get('id')

            try:
                # Проверяем, не импортирована ли уже
                existing = frappe.db.get_value('E-Taxes VAT Operations',
                                              {'operation_id': operation_id},
                                              'name')

                if existing:
                    skipped_count += 1
                    continue

                # Создаем Journal Entry
                je_result = create_journal_entry_from_vat_operation(operation, company, create_as_draft, auto_create_customers)

                if je_result.get('success'):
                    # Создаем запись отслеживания
                    record_result = create_vat_operation_record(
                        operation,
                        je_result.get('journal_entry'),
                        'Imported',
                        None
                    )

                    if record_result.get('success'):
                        success_count += 1
                    else:
                        failed_count += 1
                        errors.append({
                            'operation_id': operation_id,
                            'message': 'Journal Entry created but tracking record failed'
                        })
                else:
                    # НЕ создаем VAT Operations при ошибке - только логируем
                    failed_count += 1

                    # ДОБАВЛЯЕМ ДЕТАЛЬНУЮ ИНФОРМАЦИЮ
                    # Используем income если есть, иначе expense
                    amount = operation.get('income') or operation.get('expense')
                    error_details = {
                        'operation_id': operation_id,
                        'message': je_result.get('message'),
                        'error_type': je_result.get('error_type'),
                        # Добавляем контекстную информацию из операции
                        'tin': operation.get('tin'),
                        'customer_name': operation.get('name'),
                        'income': amount,  # Используем 'income' как поле для amount (для обратной совместимости в UI)
                        'operation_date': operation.get('operationDate'),
                        'operation_type': operation.get('operation_type')
                    }

                    # Если ошибка связана со счетами, добавляем номер счета
                    if je_result.get('error_type') == 'account_not_found':
                        error_details['account_number'] = je_result.get('account_number')

                    # Если ошибка связана с клиентом, подчеркиваем TIN
                    if je_result.get('error_type') == 'customer_not_found':
                        error_details['missing_tin'] = operation.get('tin')

                    # Если ошибка связана с отсутствием маппинга, добавляем operation_type из результата
                    if je_result.get('error_type') == 'mapping_not_found':
                        error_details['operation_type'] = je_result.get('operation_type')

                    errors.append(error_details)

            except Exception as e:
                failed_count += 1
                error_msg = f"Error processing operation {operation_id}: {str(e)}"
                frappe.log_error(error_msg, "VAT Import Error")
                errors.append({
                    'operation_id': operation_id,
                    'message': str(e)
                })

        return {
            'success': True,
            'total': total_count,
            'imported': success_count,
            'failed': failed_count,
            'skipped': skipped_count,
            'errors': errors,
            'message': f'Imported {success_count} of {total_count} operations. Failed: {failed_count}, Skipped: {skipped_count}'
        }

    except Exception as e:
        frappe.log_error(f"Error in import_vat_operations: {str(e)}\n{frappe.get_traceback()}",
                        "VAT Import Error")
        return {
            'success': False,
            'message': f'Import failed: {str(e)}'
        }


@frappe.whitelist()
def load_vat_operations_from_etaxes(date_from, date_to, max_count=50, offset=0):
    """
    Загрузка VAT операций из e-taxes (для фронтенда)

    Args:
        date_from (str): Дата начала
        date_to (str): Дата окончания
        max_count (int): Максимум записей
        offset (int): Смещение

    Returns:
        dict: Результат с операциями для обработки на фронтенде
    """
    record_etaxes_activity()

    try:
        # Получаем токен
        asan_login_settings = get_default_asan_login()

        if not asan_login_settings.get('found'):
            return {
                'success': False,
                'message': 'No Asan Login settings found'
            }

        token = asan_login_settings['main_token']

        # Загружаем операции
        response = get_vat_operations(token, date_from, date_to, max_count, offset)

        if 'error' in response:
            return {
                'success': False,
                'error': response.get('error'),
                'message': response.get('message')
            }

        operations = response.get('operations', [])
        has_more = response.get('hasMore', False)

        frappe.logger().info(f"VAT Operations loaded: {len(operations)} operations")

        return {
            'success': True,
            'operations': operations,
            'hasMore': has_more,
            'token': token,
            'total': len(operations)
        }

    except Exception as e:
        frappe.log_error(f"Error in load_vat_operations_from_etaxes: {str(e)}\n{frappe.get_traceback()}",
                        "VAT Load Error")
        return {
            'success': False,
            'message': f'Load failed: {str(e)}'
        }
