#!/usr/bin/env python3
"""Tests for ora_ops module."""

import io
import os
import sys
import tempfile
import zipfile
from pathlib import Path

from PIL import Image

# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent.parent))

from ora_editor.ora_ops import (
    load_ora, create_ora_from_png, add_masked_layer, rename_layer,
    delete_layer, reorder_layer, get_layer_visibility, set_layer_visibility,
    save_ora, parse_stack_xml, get_image_size, get_groups_and_layers
)


def test_create_ora_from_png():
    """Test creating an ORA from a PNG file."""
    # Create a simple test PNG
    test_img = Image.new('RGBA', (100, 100), (255, 0, 0, 255))
    
    with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as png_f:
        test_img.save(png_f.name)
        png_path = png_f.name

    with tempfile.NamedTemporaryFile(suffix='.ora', delete=False) as ora_f:
        ora_path = ora_f.name

    try:
        result = create_ora_from_png(png_path, ora_path)
        
        assert result['success'], f"Failed to create ORA: {result.get('error')}"
        assert os.path.exists(ora_path), "ORA file was not created"
        
        # Verify we can load it back
        loaded = load_ora(ora_path)
        assert 'layers' in loaded, "Loaded ORA has no layers"
        assert len(loaded['layers']) == 1, f"Expected 1 layer, got {len(loaded['layers'])}"
        
        print("✓ create_ora_from_png passed")
        return True
    finally:
        os.unlink(png_path)
        if os.path.exists(ora_path):
            os.unlink(ora_path)


def test_load_ora():
    """Test loading an existing ORA file."""
    with tempfile.NamedTemporaryFile(suffix='.ora', delete=False) as ora_f:
        ora_path = ora_f.name

    try:
        # Create a test PNG first
        test_img = Image.new('RGBA', (200, 150), (0, 255, 0, 255))
        
        with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as png_f:
            test_img.save(png_f.name)
            png_path = png_f.name
        
        try:
            create_ora_from_png(png_path, ora_path)
            
            loaded = load_ora(ora_path)
            
            assert loaded['width'] == 200, f"Expected width 200, got {loaded['width']}"
            assert loaded['height'] == 150, f"Expected height 150, got {loaded['height']}"
            assert len(loaded['layers']) > 0, "No layers found in ORA"
            
            print("✓ load_ora passed")
            return True
        finally:
            os.unlink(png_path)
    finally:
        if os.path.exists(ora_path):
            os.unlink(ora_path)


def test_add_masked_layer():
    """Test adding a masked layer to an ORA."""
    # Create base PNG
    base_img = Image.new('RGBA', (100, 100), (255, 0, 0, 255))
    
    with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as png_f:
        base_img.save(png_f.name)
        png_path = png_f.name

    ora_path = png_path.replace('.png', '.ora')
    
    # Create mask (white where visible, black where transparent)
    mask_img = Image.new('L', (100, 100), 255)
    
    with tempfile.NamedTemporaryFile(suffix='.mask.png', delete=False) as mask_f:
        mask_img.save(mask_f.name)
        mask_path = mask_f.name

    try:
        result = add_masked_layer(ora_path, 'door', mask_path)
        
        assert result['success'], f"Failed to add masked layer: {result.get('error')}"
        assert 'layer_name' in result, "No layer_name in result"
        assert result['layer_name'] == 'door_0', f"Expected door_0, got {result['layer_name']}"
        
        # Verify the layer was added
        loaded = load_ora(ora_path)
        layer_names = [l['name'] for l in loaded['layers']]
        assert 'base' in layer_names, "Base layer missing"
        assert 'door_0' in layer_names, "Door layer not found"
        
        print("✓ add_masked_layer passed")
        return True
    finally:
        os.unlink(png_path)
        if os.path.exists(ora_path):
            os.unlink(ora_path)
        os.unlink(mask_path)


def test_rename_layer():
    """Test renaming a layer."""
    # Create base PNG
    base_img = Image.new('RGBA', (100, 100), (255, 0, 0, 255))
    
    with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as png_f:
        base_img.save(png_f.name)
        png_path = png_f.name

    ora_path = png_path.replace('.png', '.ora')
    
    # Create mask for a new layer
    mask_img = Image.new('L', (100, 100), 255)
    with tempfile.NamedTemporaryFile(suffix='.mask.png', delete=False) as mask_f:
        mask_img.save(mask_f.name)
        mask_path = mask_f.name

    try:
        # First add a layer to rename
        result = add_masked_layer(ora_path, 'door', mask_path)
        assert result['success']
        
        # Now rename it
        result = rename_layer(ora_path, 'door_0', 'wooden_door_0')
        
        assert result['success'], f"Failed to rename: {result.get('error')}"
        
        loaded = load_ora(ora_path)
        layer_names = [l['name'] for l in loaded['layers']]
        assert 'wooden_door_0' in layer_names, "Renamed layer not found"
        assert 'door_0' not in layer_names, "Old layer name still exists"
        
        print("✓ rename_layer passed")
        return True
    finally:
        os.unlink(png_path)
        if os.path.exists(ora_path):
            os.unlink(ora_path)
        os.unlink(mask_path)


def test_delete_layer():
    """Test deleting a layer."""
    # Create base PNG
    base_img = Image.new('RGBA', (100, 100), (255, 0, 0, 255))
    
    with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as png_f:
        base_img.save(png_f.name)
        png_path = png_f.name

    ora_path = png_path.replace('.png', '.ora')
    
    # Create mask for a new layer
    mask_img = Image.new('L', (100, 100), 255)
    with tempfile.NamedTemporaryFile(suffix='.mask.png', delete=False) as mask_f:
        mask_img.save(mask_f.name)
        mask_path = mask_f.name

    try:
        # First add a layer to delete
        result = add_masked_layer(ora_path, 'door', mask_path)
        assert result['success']
        
        # Now delete it
        result = delete_layer(ora_path, 'door_0')
        
        assert result['success'], f"Failed to delete: {result.get('error')}"
        
        loaded = load_ora(ora_path)
        layer_names = [l['name'] for l in loaded['layers']]
        assert 'door_0' not in layer_names, "Deleted layer still exists"
        
        print("✓ delete_layer passed")
        return True
    finally:
        os.unlink(png_path)
        if os.path.exists(ora_path):
            os.unlink(ora_path)
        os.unlink(mask_path)


def test_reorder_layer():
    """Test reordering layers."""
    # Create base PNG
    base_img = Image.new('RGBA', (100, 100), (255, 0, 0, 255))
    
    with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as png_f:
        base_img.save(png_f.name)
        png_path = png_f.name

    ora_path = png_path.replace('.png', '.ora')
    
    # Create mask for new layers
    mask_img = Image.new('L', (100, 100), 255)
    
    layer_paths = []
    for i in range(3):
        with tempfile.NamedTemporaryFile(suffix='.mask.png', delete=False) as mask_f:
            mask_img.save(mask_f.name)
            layer_paths.append(mask_f.name)

    try:
        # Add multiple layers
        for i, mask_path in enumerate(layer_paths):
            result = add_masked_layer(ora_path, f'layer{i}', mask_path)
            assert result['success'], f"Failed to add layer {i}"
        
        # Get initial order
        loaded = load_ora(ora_path)
        initial_order = [l['name'] for l in loaded['layers']]
        
        # Move layer0_0 down (it should stay or move one position)
        result = reorder_layer(ora_path, 'layer0_0', 'down')
        assert result['success'], f"Failed to reorder: {result.get('error')}"
        
        loaded = load_ora(ora_path)
        new_order = [l['name'] for l in loaded['layers']]
        
        # Verify order changed or stayed valid
        assert len(new_order) == len(initial_order), "Layer count changed during reorder"
        
        print("✓ reorder_layer passed")
        return True
    finally:
        os.unlink(png_path)
        if os.path.exists(ora_path):
            os.unlink(ora_path)
        for path in layer_paths:
            os.unlink(path)


def test_set_layer_visibility():
    """Test setting layer visibility."""
    base_img = Image.new('RGBA', (100, 100), (255, 0, 0, 255))
    
    with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as png_f:
        base_img.save(png_f.name)
        png_path = png_f.name

    ora_path = png_path.replace('.png', '.ora')
    
    mask_img = Image.new('L', (100, 100), 255)
    with tempfile.NamedTemporaryFile(suffix='.mask.png', delete=False) as mask_f:
        mask_img.save(mask_f.name)
        mask_path = mask_f.name

    try:
        add_masked_layer(ora_path, 'door', mask_path)
        
        # Set visibility to false
        result = set_layer_visibility(ora_path, 'door_0', False)
        assert result['success'], f"Failed to set visibility: {result.get('error')}"
        
        visible = get_layer_visibility(ora_path, 'door_0')
        assert visible is False, "Layer should be hidden"
        
        # Set visibility back to true
        result = set_layer_visibility(ora_path, 'door_0', True)
        assert result['success']
        
        visible = get_layer_visibility(ora_path, 'door_0')
        assert visible is True, "Layer should be visible"
        
        print("✓ set_layer_visibility passed")
        return True
    finally:
        os.unlink(png_path)
        if os.path.exists(ora_path):
            os.unlink(ora_path)
        os.unlink(mask_path)


def test_save_ora():
    """Test saving an ORA file."""
    base_img = Image.new('RGBA', (100, 100), (255, 0, 0, 255))
    
    with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as png_f:
        base_img.save(png_f.name)
        png_path = png_f.name

    ora_path = png_path.replace('.png', '.ora')
    
    try:
        create_ora_from_png(png_path, ora_path)
        
        # Save should work without errors
        result = save_ora(ora_path)
        assert result, "Failed to save ORA"
        
        # Verify we can still load it
        loaded = load_ora(ora_path)
        assert len(loaded['layers']) > 0, "Layers missing after save"
        
        print("✓ save_ora passed")
        return True
    finally:
        os.unlink(png_path)
        if os.path.exists(ora_path):
            os.unlink(ora_path)


if __name__ == '__main__':
    tests = [
        test_create_ora_from_png,
        test_load_ora,
        test_add_masked_layer,
        test_rename_layer,
        test_delete_layer,
        test_reorder_layer,
        test_set_layer_visibility,
        test_save_ora,
    ]
    
    passed = 0
    failed = 0
    
    for test in tests:
        try:
            if test():
                passed += 1
            else:
                failed += 1
        except Exception as e:
            print(f"✗ {test.__name__} failed with exception: {e}")
            import traceback
            traceback.print_exc()
            failed += 1
    
    print(f"\n{passed}/{len(tests)} tests passed")
    
    if failed > 0:
        sys.exit(1)
