"""Tests for SirvClient - mirrors the JavaScript test suite."""

import pytest
from sirv_image.sirv_client import SirvClient


DOMAIN = 'demo.sirv.com'


# ── Constructor ─────────────────────────────────────────


class TestConstructor:
    def test_requires_domain(self):
        with pytest.raises(ValueError, match='domain is required'):
            SirvClient()
        with pytest.raises(ValueError, match='domain is required'):
            SirvClient(domain='')

    def test_with_domain_only(self):
        sirv = SirvClient(domain=DOMAIN)
        assert sirv.url('/image.jpg') == 'https://demo.sirv.com/image.jpg'

    def test_strips_trailing_slash_from_domain(self):
        sirv = SirvClient(domain='demo.sirv.com/')
        assert sirv.url('/image.jpg') == 'https://demo.sirv.com/image.jpg'

    def test_with_defaults(self):
        sirv = SirvClient(domain=DOMAIN, defaults={'q': 80})
        assert sirv.url('/image.jpg') == 'https://demo.sirv.com/image.jpg?q=80'


# ── url() ──────────────────────────────────────────────


class TestUrl:
    def test_with_simple_params(self):
        sirv = SirvClient(domain=DOMAIN)
        url = sirv.url('/image.jpg', {'w': 300, 'h': 200, 'format': 'webp'})
        assert url == 'https://demo.sirv.com/image.jpg?w=300&h=200&format=webp'

    def test_merges_defaults_with_params(self):
        sirv = SirvClient(domain=DOMAIN, defaults={'q': 80})
        url = sirv.url('/image.jpg', {'w': 300, 'h': 200, 'format': 'webp'})
        assert url == 'https://demo.sirv.com/image.jpg?q=80&w=300&h=200&format=webp'

    def test_params_override_defaults(self):
        sirv = SirvClient(domain=DOMAIN, defaults={'q': 80})
        url = sirv.url('/image.jpg', {'q': 90})
        assert url == 'https://demo.sirv.com/image.jpg?q=90'

    def test_nested_params_flatten_to_dot_notation(self):
        sirv = SirvClient(domain=DOMAIN)
        url = sirv.url('/image.jpg', {
            'crop': {'type': 'face', 'pad': {'width': 10, 'height': 10}}
        })
        assert 'crop.type=face' in url
        assert 'crop.pad.width=10' in url
        assert 'crop.pad.height=10' in url

    def test_deeply_nested_params(self):
        sirv = SirvClient(domain=DOMAIN)
        url = sirv.url('/image.jpg', {
            'text': {'font': {'family': 'Arial', 'size': 24}, 'color': 'white'}
        })
        assert 'text.font.family=Arial' in url
        assert 'text.font.size=24' in url
        assert 'text.color=white' in url

    def test_adds_leading_slash_if_missing(self):
        sirv = SirvClient(domain=DOMAIN)
        assert sirv.url('image.jpg') == 'https://demo.sirv.com/image.jpg'

    def test_no_params_returns_clean_url(self):
        sirv = SirvClient(domain=DOMAIN)
        assert sirv.url('/image.jpg') == 'https://demo.sirv.com/image.jpg'

    def test_encodes_special_characters(self):
        sirv = SirvClient(domain=DOMAIN)
        url = sirv.url('/image.jpg', {'subsampling': '4:2:0'})
        assert 'subsampling=4%3A2%3A0' in url


# ── src_set() ───────────────────────────────────────────


class TestSrcSet:
    def test_with_explicit_widths(self):
        sirv = SirvClient(domain=DOMAIN)
        srcset = sirv.src_set('/image.jpg', {'format': 'webp'}, widths=[320, 640, 960])
        assert 'w=320 320w' in srcset
        assert 'w=640 640w' in srcset
        assert 'w=960 960w' in srcset
        assert 'format=webp' in srcset

    def test_with_min_max_width_tolerance(self):
        sirv = SirvClient(domain=DOMAIN)
        srcset = sirv.src_set(
            '/image.jpg', {'format': 'webp'},
            min_width=200, max_width=2000, tolerance=0.15,
        )
        entries = srcset.split(', ')
        assert len(entries) > 2
        # First width should be ~200, last should be ~2000
        assert 'w=200' in entries[0]
        assert 'w=2000' in entries[-1]

    def test_with_device_pixel_ratios(self):
        sirv = SirvClient(domain=DOMAIN, defaults={'q': 80})
        srcset = sirv.src_set(
            '/hero.jpg', {'w': 600, 'h': 400},
            device_pixel_ratios=[1, 2, 3],
        )
        assert '1x' in srcset
        assert '2x' in srcset
        assert '3x' in srcset
        # 1x should have q=80
        assert 'q=80' in srcset
        # 2x should have w=1200
        assert 'w=1200' in srcset
        # 3x should have w=1800
        assert 'w=1800' in srcset

    def test_dpr_uses_variable_quality(self):
        sirv = SirvClient(domain=DOMAIN, defaults={'q': 80})
        srcset = sirv.src_set(
            '/hero.jpg', {'w': 600},
            device_pixel_ratios=[1, 2, 3],
        )
        # q=80 at 1x, q=60 at 2x, q=45 at 3x (80 * 0.75^(dpr-1))
        entries = srcset.split(', ')
        assert 'q=80' in entries[0]
        assert 'q=60' in entries[1]

    def test_returns_empty_string_with_no_options(self):
        sirv = SirvClient(domain=DOMAIN)
        assert sirv.src_set('/image.jpg') == ''


# ── image() ────────────────────────────────────────────


class TestImage:
    def test_generates_img_tag(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.image('/tomatoes.jpg', alt='Fresh tomatoes')
        assert html == '<img class="Sirv" data-src="https://demo.sirv.com/tomatoes.jpg" alt="Fresh tomatoes">'

    def test_with_transform_params(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.image('/photo.jpg', transform={'w': 300, 'format': 'webp'})
        assert 'data-src="https://demo.sirv.com/photo.jpg?w=300&amp;format=webp"' in html

    def test_with_viewer_options(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.image('/photo.jpg', viewer={'autostart': 'visible', 'threshold': 200})
        assert 'data-options="autostart:visible;threshold:200"' in html

    def test_with_custom_class_name(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.image('/photo.jpg', class_name='hero-image')
        assert 'class="Sirv hero-image"' in html

    def test_with_empty_alt(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.image('/photo.jpg', alt='')
        assert 'alt=""' in html


# ── zoom() ─────────────────────────────────────────────


class TestZoom:
    def test_generates_div_with_data_type_zoom(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.zoom('/product.jpg')
        assert html == '<div class="Sirv" data-src="https://demo.sirv.com/product.jpg" data-type="zoom"></div>'

    def test_with_viewer_options(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.zoom('/product.jpg', viewer={'mode': 'deep', 'wheel': False})
        assert 'data-type="zoom"' in html
        assert 'data-options="mode:deep;wheel:False"' in html


# ── spin() ─────────────────────────────────────────────


class TestSpin:
    def test_generates_div_without_data_type(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.spin('/product.spin')
        assert html == '<div class="Sirv" data-src="https://demo.sirv.com/product.spin"></div>'
        assert 'data-type' not in html

    def test_with_viewer_options(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.spin('/product.spin', viewer={'autostart': 'visible', 'autospin': 'lazy'})
        assert 'data-options="autostart:visible;autospin:lazy"' in html


# ── video() ────────────────────────────────────────────


class TestVideo:
    def test_generates_div_without_data_type(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.video('/clip.mp4')
        assert html == '<div class="Sirv" data-src="https://demo.sirv.com/clip.mp4"></div>'


# ── model() ────────────────────────────────────────────


class TestModel:
    def test_generates_div_without_data_type(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.model('/shoe.glb')
        assert html == '<div class="Sirv" data-src="https://demo.sirv.com/shoe.glb"></div>'


# ── gallery() ──────────────────────────────────────────


class TestGallery:
    def test_generates_nested_divs(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.gallery([
            {'src': '/product.spin'},
            {'src': '/front.jpg', 'type': 'zoom'},
        ])
        assert '<div class="Sirv">' in html
        assert 'data-src="https://demo.sirv.com/product.spin"' in html
        assert 'data-src="https://demo.sirv.com/front.jpg" data-type="zoom"' in html
        assert html.endswith('</div></div>')

    def test_with_gallery_level_viewer_options(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.gallery(
            [{'src': '/image1.jpg'}],
            viewer={'arrows': True, 'thumbnails': 'bottom'},
        )
        assert 'data-options="arrows:True;thumbnails:bottom"' in html

    def test_with_per_item_viewer_options(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.gallery([
            {'src': '/product.jpg', 'type': 'zoom', 'viewer': {'mode': 'deep'}},
        ])
        assert 'data-type="zoom"' in html
        assert 'data-options="mode:deep"' in html

    def test_with_per_item_transforms(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.gallery([
            {'src': '/photo.jpg', 'transform': {'w': 800, 'format': 'webp'}},
        ])
        assert 'w=800' in html
        assert 'format=webp' in html

    def test_with_custom_class_name(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.gallery([{'src': '/img.jpg'}], class_name='product-gallery')
        assert 'class="Sirv product-gallery"' in html


# ── script_tag() ────────────────────────────────────────


class TestScriptTag:
    def test_with_no_modules(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.script_tag()
        assert html == '<script src="https://scripts.sirv.com/sirvjs/v3/sirv.js" async></script>'

    def test_with_modules(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.script_tag(modules=['spin', 'zoom'])
        assert html == '<script src="https://scripts.sirv.com/sirvjs/v3/sirv.spin.zoom.js" async></script>'

    def test_without_async(self):
        sirv = SirvClient(domain=DOMAIN)
        html = sirv.script_tag(async_attr=False)
        assert html == '<script src="https://scripts.sirv.com/sirvjs/v3/sirv.js"></script>'
