import io
import json
import logging
from pathlib import Path
from typing import Any

logger = logging.getLogger(__name__)


class VacancyParserService:
    """Сервис для парсинга вакансий из файлов различных форматов"""

    def __init__(self):
        self.supported_formats = [".pdf", ".docx", ".rtf", ".txt"]

    def extract_text_from_file(self, file_content: bytes, filename: str) -> str:
        """
        Извлекает текст из файла в зависимости от его формата

        Args:
            file_content: Содержимое файла в байтах
            filename: Имя файла для определения формата

        Returns:
            str: Извлеченный текст
        """
        file_extension = Path(filename).suffix.lower()

        try:
            if file_extension == ".pdf":
                return self._extract_from_pdf(file_content)
            elif file_extension == ".docx":
                return self._extract_from_docx(file_content)
            elif file_extension == ".rtf":
                return self._extract_from_rtf(file_content)
            elif file_extension == ".txt":
                return self._extract_from_txt(file_content)
            else:
                raise ValueError(f"Неподдерживаемый формат файла: {file_extension}")

        except Exception as e:
            logger.error(f"Ошибка при извлечении текста из файла {filename}: {str(e)}")
            raise

    def _extract_from_pdf(self, file_content: bytes) -> str:
        """Извлекает текст из PDF файла"""
        try:
            import PyPDF2

            pdf_file = io.BytesIO(file_content)
            pdf_reader = PyPDF2.PdfReader(pdf_file)

            text = ""
            for page in pdf_reader.pages:
                text += page.extract_text() + "\n"

            return text.strip()

        except ImportError:
            # Fallback to pdfplumber if PyPDF2 doesn't work well
            try:
                import pdfplumber

                pdf_file = io.BytesIO(file_content)
                text = ""

                with pdfplumber.open(pdf_file) as pdf:
                    for page in pdf.pages:
                        page_text = page.extract_text()
                        if page_text:
                            text += page_text + "\n"

                return text.strip()

            except ImportError:
                raise ImportError(
                    "Требуется установить PyPDF2 или pdfplumber: pip install PyPDF2 pdfplumber"
                )

    def _extract_from_docx(self, file_content: bytes) -> str:
        """Извлекает текст из DOCX файла"""
        try:
            import docx

            doc_file = io.BytesIO(file_content)
            doc = docx.Document(doc_file)

            text = ""
            for paragraph in doc.paragraphs:
                text += paragraph.text + "\n"

            # Также извлекаем текст из таблиц
            for table in doc.tables:
                for row in table.rows:
                    for cell in row.cells:
                        text += cell.text + "\t"
                    text += "\n"

            return text.strip()

        except ImportError:
            raise ImportError(
                "Требуется установить python-docx: pip install python-docx"
            )

    def _extract_from_rtf(self, file_content: bytes) -> str:
        """Извлекает текст из RTF файла"""
        try:
            from striprtf.striprtf import rtf_to_text

            rtf_content = file_content.decode("utf-8", errors="ignore")
            text = rtf_to_text(rtf_content)

            return text.strip()

        except ImportError:
            raise ImportError("Требуется установить striprtf: pip install striprtf")
        except Exception:
            # Альтернативный метод через pyth
            try:
                from pyth.plugins.plaintext.writer import PlaintextWriter
                from pyth.plugins.rtf15.reader import Rtf15Reader

                doc = Rtf15Reader.read(io.BytesIO(file_content))
                text = PlaintextWriter.write(doc).getvalue()

                return text.strip()

            except ImportError:
                raise ImportError(
                    "Требуется установить striprtf или pyth: pip install striprtf pyth"
                )

    def _extract_from_txt(self, file_content: bytes) -> str:
        """Извлекает текст из TXT файла"""
        try:
            # Пробуем различные кодировки
            encodings = ["utf-8", "windows-1251", "cp1252", "iso-8859-1"]

            for encoding in encodings:
                try:
                    text = file_content.decode(encoding)
                    return text.strip()
                except UnicodeDecodeError:
                    continue

            # Если все кодировки не подошли, используем errors='ignore'
            text = file_content.decode("utf-8", errors="ignore")
            return text.strip()

        except Exception as e:
            logger.error(f"Ошибка при чтении txt файла: {str(e)}")
            raise

    async def parse_vacancy_with_ai(self, raw_text: str) -> dict[str, Any]:
        """
        Парсит текст вакансии с помощью AI для извлечения структурированной информации

        Args:
            raw_text: Сырой текст вакансии

        Returns:
            Dict с полями для модели Vacancy
        """
        from rag.settings import settings

        if not settings.openai_api_key:
            raise ValueError("OpenAI API ключ не настроен")

        try:
            import openai

            openai.api_key = settings.openai_api_key

            parsing_prompt = f"""
Проанализируй текст вакансии и извлеки из него структурированную информацию.

ТЕКСТ ВАКАНСИИ:
{raw_text}

ЗАДАЧА:
Извлеки следующие поля для вакансии:

1. title - название позиции (строка)
2. description - описание вакансии (полное описание обязанностей, требований)
3. key_skills - ключевые навыки через запятую (строка)
4. employment_type - тип занятости: "full", "part", "project", "volunteer", "probation"
5. experience - опыт работы: "noExperience", "between1And3", "between3And6", "moreThan6"
6. schedule - график работы: "fullDay", "shift", "flexible", "remote", "flyInFlyOut"
7. salary_from - зарплата от (число или null)
8. salary_to - зарплата до (число или null)  
9. salary_currency - валюта (строка, по умолчанию "RUR")
10. company_name - название компании (строка)
11. company_description - описание компании (строка или null)
12. area_name - город/регион (строка)
13. address - адрес (строка или null)
14. professional_roles - профессиональные роли (строка или null)
15. contacts_name - контактное лицо (строка или null)
16. contacts_email - email для связи (строка или null)
17. contacts_phone - телефон для связи (строка или null)

ПРАВИЛА:
- Если информация не найдена, ставь null для необязательных полей
- Для обязательных полей используй разумные значения по умолчанию
- Зарплату указывай в рублях, конвертируй если нужно
- Опыт определяй по годам: 0-1 = noExperience, 1-3 = between1And3, 3-6 = between3And6, 6+ = moreThan6
- График работы определяй по описанию: офис = fullDay, удаленка = remote, гибкий = flexible

ФОРМАТИРОВАНИЕ ТЕКСТА:
- Если в тексте есть списки (обязанности, требования, навыки), форматируй их с переносами строк
- Используй символ \n для переноса строки между пунктами списка
- Пример: "Обязанности:\nВедение переговоров\nПодготовка документов\nОбучение персонала"
- Для ключевых навыков разделяй запятыми, но если их много - используй переносы строк
- В описании компании тоже используй переносы для лучшей читаемости

ОТВЕТЬ СТРОГО В JSON ФОРМАТЕ с указанными полями:
"""

            response = openai.chat.completions.create(
                model="gpt-4o-mini",
                messages=[{"role": "user", "content": parsing_prompt}],
                response_format={"type": "json_object"},
            )

            parsed_data = json.loads(response.choices[0].message.content)

            # Валидируем и обрабатываем данные
            return self._validate_parsed_data(parsed_data)

        except Exception as e:
            logger.error(f"Ошибка при парсинге вакансии через AI: {str(e)}")
            raise

    def _validate_parsed_data(self, data: dict[str, Any]) -> dict[str, Any]:
        """Валидирует и очищает спарсенные данные"""
        from app.models.vacancy import EmploymentType, Experience, Schedule

        # Обязательные поля с дефолтными значениями
        validated_data = {
            "title": data.get("title", "Название не указано"),
            "description": data.get("description", "Описание не указано"),
            "key_skills": data.get("key_skills"),
            "employment_type": self._validate_enum(
                data.get("employment_type"), EmploymentType, EmploymentType.FULL_TIME
            ),
            "experience": self._validate_enum(
                data.get("experience"), Experience, Experience.BETWEEN_1_AND_3
            ),
            "schedule": self._validate_enum(
                data.get("schedule"), Schedule, Schedule.FULL_DAY
            ),
            "company_name": data.get("company_name"),
            "area_name": data.get("area_name"),
        }

        # Необязательные поля
        optional_fields = [
            "salary_from",
            "salary_to",
            "salary_currency",
            "company_description",
            "address",
            "professional_roles",
            "contacts_name",
            "contacts_email",
            "contacts_phone",
        ]

        for field in optional_fields:
            value = data.get(field)
            if value and value != "null":
                validated_data[field] = value

        # Специальная обработка зарплаты
        if data.get("salary_from"):
            try:
                validated_data["salary_from"] = int(data["salary_from"])
            except (ValueError, TypeError):
                pass

        if data.get("salary_to"):
            try:
                validated_data["salary_to"] = int(data["salary_to"])
            except (ValueError, TypeError):
                pass

        # Валюта по умолчанию
        validated_data["salary_currency"] = data.get("salary_currency", "RUR")

        return validated_data

    def _validate_enum(self, value: str, enum_class, default_value):
        """Валидирует значение enum"""
        if not value:
            return default_value

        # Проверяем, есть ли такое значение в enum
        try:
            return enum_class(value)
        except ValueError:
            logger.warning(
                f"Неизвестное значение {value} для {enum_class.__name__}, используем {default_value}"
            )
            return default_value


# Экземпляр сервиса
vacancy_parser_service = VacancyParserService()
