"""
表单数据提取器
提取和填充表单
"""
from typing import Optional, List, Dict, Any
from playwright.async_api import Page
from loguru import logger


class FormDataExtractor:
    """
    表单数据提取器
    提取和填充表单
    """

    def __init__(self, page: Page):
        self.page = page

    async def extract_all_inputs(self) -> List[Dict[str, Any]]:
        """提取所有输入框信息"""
        inputs = await self.page.evaluate("""
            () => {
                const results = [];
                document.querySelectorAll('input, textarea, select').forEach(el => {
                    const info = {
                        tag: el.tagName.toLowerCase(),
                        type: el.type || el.tagName.toLowerCase(),
                        name: el.name || '',
                        id: el.id || '',
                        placeholder: el.placeholder || '',
                        value: el.value || '',
                        required: el.required,
                        disabled: el.disabled,
                        readonly: el.readOnly,
                        label: '',
                    };

                    // 获取关联的 label
                    if (el.id) {
                        const label = document.querySelector(`label[for="${el.id}"]`);
                        if (label) info.label = label.textContent.trim();
                    }

                    // 对于 select，获取选项
                    if (el.tagName.toLowerCase() === 'select') {
                        info.options = Array.from(el.options).map(opt => ({
                            value: opt.value,
                            text: opt.textContent.trim(),
                            selected: opt.selected,
                        }));
                    }

                    results.push(info);
                });
                return results;
            }
        """)
        return inputs

    async def extract_form_data(self, form_selector: str = "form") -> Dict[str, Any]:
        """提取表单数据"""
        form_data = await self.page.evaluate(f"""
            () => {{
                const form = document.querySelector('{form_selector}');
                if (!form) return {{}};

                const data = {{}};
                const formData = new FormData(form);

                for (let [key, value] of formData.entries()) {{
                    if (data[key]) {{
                        if (!Array.isArray(data[key])) {{
                            data[key] = [data[key]];
                        }}
                        data[key].push(value);
                    }} else {{
                        data[key] = value;
                    }}
                }}

                return data;
            }}
        """)
        return form_data

    async def extract_checkbox_states(self) -> List[Dict[str, Any]]:
        """提取所有复选框状态"""
        checkboxes = await self.page.evaluate("""
            () => {
                const results = [];
                document.querySelectorAll('input[type="checkbox"], input[type="radio"]').forEach(el => {
                    results.push({
                        name: el.name || '',
                        id: el.id || '',
                        value: el.value || '',
                        checked: el.checked,
                        type: el.type,
                        label: el.labels?.[0]?.textContent.trim() || '',
                    });
                });
                return results;
            }
        """)
        return checkboxes

    async def extract_select_options(self, select_selector: str) -> List[Dict[str, str]]:
        """提取下拉框选项"""
        options = await self.page.evaluate(f"""
            () => {{
                const select = document.querySelector('{select_selector}');
                if (!select) return [];

                return Array.from(select.options).map(opt => ({{
                    value: opt.value,
                    text: opt.textContent.trim(),
                    selected: opt.selected,
                }}));
            }}
        """)
        return options

    async def extract_file_inputs(self) -> List[Dict[str, Any]]:
        """提取文件上传输入框信息"""
        file_inputs = await self.page.evaluate("""
            () => {
                const results = [];
                document.querySelectorAll('input[type="file"]').forEach(el => {
                    results.push({
                        name: el.name || '',
                        id: el.id || '',
                        accept: el.accept || '',
                        multiple: el.multiple,
                        required: el.required,
                        label: el.labels?.[0]?.textContent.trim() || '',
                    });
                });
                return results;
            }
        """)
        return file_inputs

    async def extract_hidden_fields(self) -> Dict[str, str]:
        """提取隐藏字段"""
        hidden = await self.page.evaluate("""
            () => {
                const results = {};
                document.querySelectorAll('input[type="hidden"]').forEach(el => {
                    if (el.name) {
                        results[el.name] = el.value;
                    }
                });
                return results;
            }
        """)
        return hidden

    async def extract_form_errors(self, error_selector: str = ".error, .error-message, .invalid-feedback") -> List[Dict[str, str]]:
        """提取表单验证错误信息"""
        errors = await self.page.evaluate(f"""
            () => {{
                const results = [];
                document.querySelectorAll('{error_selector}').forEach(el => {{
                    const text = el.textContent.trim();
                    if (text) {{
                        const parent = el.closest('.form-group, .input-group, [class*="field"]');
                        const input = parent?.querySelector('input, select, textarea');

                        results.push({{
                            message: text,
                            field: input?.name || input?.id || '',
                            visible: el.offsetParent !== null,
                        }});
                    }}
                }});
                return results;
            }}
        """)
        return errors

    async def fill_form(
        self,
        data: Dict[str, Any],
        form_selector: str = "form",
        submit: bool = False,
        submit_selector: Optional[str] = None,
    ) -> bool:
        """
        填充表单

        Args:
            data: 表单数据 {字段名: 值}
            form_selector: 表单选择器
            submit: 是否提交
            submit_selector: 提交按钮选择器

        Returns:
            是否成功
        """
        try:
            form = self.page.locator(form_selector)

            for field_name, value in data.items():
                # 尝试多种选择器
                selectors = [
                    f'[name="{field_name}"]',
                    f'#{field_name}',
                    f'[id="{field_name}"]',
                ]

                for selector in selectors:
                    element = form.locator(selector)
                    if await element.count() > 0:
                        # 判断输入类型
                        tag = await element.evaluate("el => el.tagName.toLowerCase()")
                        input_type = await element.evaluate("el => el.type || ''")

                        if tag == "select":
                            await element.select_option(value=str(value))
                        elif input_type == "checkbox":
                            if value:
                                await element.check()
                            else:
                                await element.uncheck()
                        elif input_type == "radio":
                            await element.check()
                        elif input_type == "file":
                            await element.set_input_files(value)
                        else:
                            await element.fill(str(value))
                        break

            if submit:
                if submit_selector:
                    await self.page.locator(submit_selector).click()
                else:
                    await form.locator('button[type="submit"], input[type="submit"]').click()

            return True
        except Exception as e:
            logger.error(f"填充表单失败: {e}")
            return False

    async def clear_form(self, form_selector: str = "form") -> bool:
        """清空表单 - 批量优化版"""
        try:
            # 在浏览器端批量清空所有表单元素
            await self.page.evaluate(f"""
                () => {{
                    const form = document.querySelector('{form_selector}');
                    if (!form) return;

                    // 清空所有文本输入
                    form.querySelectorAll('input[type="text"], input[type="email"], input[type="password"], input[type="tel"], input[type="url"], textarea').forEach(el => {{
                        el.value = '';
                    }});

                    // 取消所有复选框
                    form.querySelectorAll('input[type="checkbox"]').forEach(el => {{
                        el.checked = false;
                    }});

                    // 取消所有单选框
                    form.querySelectorAll('input[type="radio"]').forEach(el => {{
                        el.checked = false;
                    }});

                    // 重置下拉框
                    form.querySelectorAll('select').forEach(el => {{
                        if (el.options.length > 0) {{
                            el.selectedIndex = 0;
                        }}
                    }});
                }}
            """)
            return True
        except Exception as e:
            logger.error(f"清空表单失败: {e}")
            return False

    async def validate_form(self, form_selector: str = "form") -> Dict[str, Any]:
        """
        验证表单

        Returns:
            验证结果 {valid: bool, errors: []}
        """
        inputs = await self.extract_all_inputs()
        errors = []

        for inp in inputs:
            if inp.get('required') and not inp.get('value'):
                field_label = inp.get('label') or inp.get('name') or inp.get('id')
                errors.append({
                    'field': field_label,
                    'message': '此字段为必填项',
                })

        return {
            'valid': len(errors) == 0,
            'errors': errors,
        }
