"""Export code-use session to Jupyter notebook format."""

import json
import re
from pathlib import Path

from openbrowser.code_use.service import CodeAgent

from .views import CellType, NotebookExport


def export_to_ipynb(agent: CodeAgent, output_path: str | Path) -> Path:
	"""
	Export a NotebookSession to a Jupyter notebook (.ipynb) file.
	Now includes JavaScript code blocks that were stored in the namespace.

	Args:
		session: The NotebookSession to export
		output_path: Path where to save the notebook file
		agent: Optional CodeAgent instance to access namespace for JavaScript blocks

	Returns:
		Path to the saved notebook file

	Example:
		```python
	        session = await agent.run()
	        notebook_path = export_to_ipynb(agent, 'my_automation.ipynb')
	        print(f'Notebook saved to {notebook_path}')
		```
	"""
	output_path = Path(output_path)

	# Create notebook structure
	notebook = NotebookExport(
		metadata={
			'kernelspec': {'display_name': 'Python 3', 'language': 'python', 'name': 'python3'},
			'language_info': {
				'name': 'python',
				'version': '3.11.0',
				'mimetype': 'text/x-python',
				'codemirror_mode': {'name': 'ipython', 'version': 3},
				'pygments_lexer': 'ipython3',
				'nbconvert_exporter': 'python',
				'file_extension': '.py',
			},
		}
	)

	# Add setup cell at the beginning with proper type hints
	setup_code = """import asyncio
import json
from typing import Any
from openbrowser import BrowserSession
from openbrowser.code_use import create_namespace

# Initialize browser and namespace
browser = BrowserSession()
await browser.start()

# Create namespace with all browser control functions
namespace: dict[str, Any] = create_namespace(browser)

# Import all functions into the current namespace
globals().update(namespace)

# Type hints for better IDE support (these are now available globally)
# navigate, click, input, evaluate, search, extract, scroll, done, etc.

	print("OpenBrowser environment initialized!")
print("Available functions: navigate, click, input, evaluate, search, extract, done, etc.")"""

	setup_cell = {
		'cell_type': 'code',
		'metadata': {},
		'source': setup_code.split('\n'),
		'execution_count': None,
		'outputs': [],
	}
	notebook.cells.append(setup_cell)

	# Add JavaScript code blocks as variables FIRST
	if hasattr(agent, 'namespace') and agent.namespace:
		# Look for JavaScript variables in the namespace
		code_block_vars = agent.namespace.get('_code_block_vars', set())

		for var_name in sorted(code_block_vars):
			var_value = agent.namespace.get(var_name)
			if isinstance(var_value, str) and var_value.strip():
				# Check if this looks like JavaScript code
				# Look for common JS patterns
				js_patterns = [
					r'function\s+\w+\s*\(',
					r'\(\s*function\s*\(\)',
					r'=>\s*{',
					r'document\.',
					r'Array\.from\(',
					r'\.querySelector',
					r'\.textContent',
					r'\.innerHTML',
					r'return\s+',
					r'console\.log',
					r'window\.',
					r'\.map\(',
					r'\.filter\(',
					r'\.forEach\(',
				]

				is_js = any(re.search(pattern, var_value, re.IGNORECASE) for pattern in js_patterns)

				if is_js:
					# Create a code cell with the JavaScript variable
					js_cell = {
						'cell_type': 'code',
						'metadata': {},
						'source': [f'# JavaScript Code Block: {var_name}\n', f'{var_name} = """{var_value}"""'],
						'execution_count': None,
						'outputs': [],
					}
					notebook.cells.append(js_cell)

	# Convert cells
	python_cell_count = 0
	for cell in agent.session.cells:
		notebook_cell: dict = {
			'cell_type': cell.cell_type.value,
			'metadata': {},
			'source': cell.source.splitlines(keepends=True),
		}

		if cell.cell_type == CellType.CODE:
			python_cell_count += 1
			notebook_cell['execution_count'] = cell.execution_count
			notebook_cell['outputs'] = []

			# Add output if available
			if cell.output:
				notebook_cell['outputs'].append(
					{
						'output_type': 'stream',
						'name': 'stdout',
						'text': cell.output.split('\n'),
					}
				)

			# Add error if available
			if cell.error:
				notebook_cell['outputs'].append(
					{
						'output_type': 'error',
						'ename': 'Error',
						'evalue': cell.error.split('\n')[0] if cell.error else '',
						'traceback': cell.error.split('\n') if cell.error else [],
					}
				)

			# Add browser state as a separate output
			if cell.browser_state:
				notebook_cell['outputs'].append(
					{
						'output_type': 'stream',
						'name': 'stdout',
						'text': [f'Browser State:\n{cell.browser_state}'],
					}
				)

		notebook.cells.append(notebook_cell)

	# Write to file
	output_path.parent.mkdir(parents=True, exist_ok=True)
	with open(output_path, 'w', encoding='utf-8') as f:
		json.dump(notebook.model_dump(), f, indent=2, ensure_ascii=False)

	return output_path


def session_to_python_script(agent: CodeAgent) -> str:
	"""
	Convert a CodeAgent session to a Python script.
	Now includes JavaScript code blocks that were stored in the namespace.

	Args:
		agent: The CodeAgent instance to convert

	Returns:
		Python script as a string

	Example:
		```python
	        await agent.run()
	        script = session_to_python_script(agent)
	        print(script)
		```
	"""
	lines = []

	lines.append('# Generated from openbrowser code-use session\n')
	lines.append('import asyncio\n')
	lines.append('import json\n')
	lines.append('from openbrowser import BrowserSession\n')
	lines.append('from openbrowser.code_use import create_namespace\n\n')

	lines.append('async def main():\n')
	lines.append('\t# Initialize browser and namespace\n')
	lines.append('\tbrowser = BrowserSession()\n')
	lines.append('\tawait browser.start()\n\n')
	lines.append('\t# Create namespace with all browser control functions\n')
	lines.append('\tnamespace = create_namespace(browser)\n\n')
	lines.append('\t# Extract functions from namespace for direct access\n')
	lines.append('\tnavigate = namespace["navigate"]\n')
	lines.append('\tclick = namespace["click"]\n')
	lines.append('\tinput_text = namespace["input"]\n')
	lines.append('\tevaluate = namespace["evaluate"]\n')
	lines.append('\tsearch = namespace["search"]\n')
	lines.append('\textract = namespace["extract"]\n')
	lines.append('\tscroll = namespace["scroll"]\n')
	lines.append('\tdone = namespace["done"]\n')
	lines.append('\tgo_back = namespace["go_back"]\n')
	lines.append('\twait = namespace["wait"]\n')
	lines.append('\tscreenshot = namespace["screenshot"]\n')
	lines.append('\tfind_text = namespace["find_text"]\n')
	lines.append('\tswitch_tab = namespace["switch"]\n')
	lines.append('\tclose_tab = namespace["close"]\n')
	lines.append('\tdropdown_options = namespace["dropdown_options"]\n')
	lines.append('\tselect_dropdown = namespace["select_dropdown"]\n')
	lines.append('\tupload_file = namespace["upload_file"]\n')
	lines.append('\tsend_keys = namespace["send_keys"]\n\n')

	# Add JavaScript code blocks as variables FIRST
	if hasattr(agent, 'namespace') and agent.namespace:
		code_block_vars = agent.namespace.get('_code_block_vars', set())

		for var_name in sorted(code_block_vars):
			var_value = agent.namespace.get(var_name)
			if isinstance(var_value, str) and var_value.strip():
				# Check if this looks like JavaScript code
				js_patterns = [
					r'function\s+\w+\s*\(',
					r'\(\s*function\s*\(\)',
					r'=>\s*{',
					r'document\.',
					r'Array\.from\(',
					r'\.querySelector',
					r'\.textContent',
					r'\.innerHTML',
					r'return\s+',
					r'console\.log',
					r'window\.',
					r'\.map\(',
					r'\.filter\(',
					r'\.forEach\(',
				]

				is_js = any(re.search(pattern, var_value, re.IGNORECASE) for pattern in js_patterns)

				if is_js:
					lines.append(f'\t# JavaScript Code Block: {var_name}\n')
					lines.append(f'\t{var_name} = """{var_value}"""\n\n')

	for i, cell in enumerate(agent.session.cells):
		if cell.cell_type == CellType.CODE:
			lines.append(f'\t# Cell {i + 1}\n')

			# Indent each line of source
			source_lines = cell.source.split('\n')
			for line in source_lines:
				if line.strip():  # Only add non-empty lines
					lines.append(f'\t{line}\n')

			lines.append('\n')

	lines.append('\tawait browser.stop()\n\n')
	lines.append("if __name__ == '__main__':\n")
	lines.append('\tasyncio.run(main())\n')

	return ''.join(lines)
