"""Matching board portraits to the right person.

The board pages float each portrait to the right of the text, and whether the
image sits above or below its name heading varies between the three sites and
even within a single page. Taking the image that falls between two headings
therefore gives one member another member's face — which is what happened: a
sitting director appeared under a different sitting director's name.

So photos are matched on the filename, and an image that matches nobody is
dropped rather than handed to whoever is nearest.
"""
from django.test import TestCase

from documents.management.commands.import_board import parse_members

AFTER = """
<h3>Charles Edward Dickson</h3>
<p><strong>Chair</strong></p>
<figure><img src="/wp-content/uploads/2018/01/charlesdickson2018.jpg"></figure>
<p>A long biography sentence about the chair.</p>
<h3>Stan Hartling</h3>
<figure><img src="/wp-content/uploads/2019/03/stan200x300.jpg"></figure>
<p>A long biography sentence about Stan.</p>
"""

BEFORE = """
<figure><img src="/wp-content/uploads/2017/05/mileshammL.jpg"></figure>
<h3>Miles Hamm</h3>
<p>A long biography sentence about Miles.</p>
<figure><img src="/wp-content/uploads/2019/03/stan200x300.jpg"></figure>
<h3>Stan Hartling</h3>
<p>A long biography sentence about Stan.</p>
<figure><img src="/wp-content/uploads/2016/02/tommothorpeL.jpg"></figure>
<h3>Tom Mothorpe</h3>
<p>A long biography sentence about Tom.</p>
"""


def photo_of(members, name):
    for member in members:
        if member["name"] == name:
            return (member["photo"] or "").rsplit("/", 1)[-1]
    raise AssertionError("%s was not parsed at all" % name)


class RoleParsingTests(TestCase):
    def test_a_line_break_does_not_weld_the_role_to_what_follows(self):
        """<br> is a line break, not nothing.

        Stripping it outright joined "…Board of Directors" to "The Sands at
        Grace Bay" as one 54-character run, which then failed the length test
        for a role and was silently filed as biography — the member showed no
        role at all.
        """
        markup = """
        <h3>Wes Stearns</h3>
        <p>Candidate for Board of Directors<br><em>The Sands at Grace Bay</em></p>
        <p>A long biography sentence about Wes.</p>
        """
        member = parse_members(markup)[0]
        self.assertEqual(member["role"], "Candidate for Board of Directors")

    def test_what_followed_the_break_is_kept(self):
        markup = """
        <h3>Wes Stearns</h3>
        <p>Candidate for Board of Directors<br><em>The Sands at Grace Bay</em></p>
        """
        self.assertIn("The Sands at Grace Bay", parse_members(markup)[0]["bio"])

    def test_a_plain_role_line_is_unaffected(self):
        markup = """
        <h3>Miles Hamm</h3>
        <p>Chairperson</p>
        <p>A long biography sentence about Miles.</p>
        """
        self.assertEqual(parse_members(markup)[0]["role"], "Chairperson")


class BoardPhotoMatchingTests(TestCase):
    def test_photo_below_the_name(self):
        members = parse_members(AFTER)
        self.assertEqual(photo_of(members, "Charles Edward Dickson"), "charlesdickson2018.jpg")
        self.assertEqual(photo_of(members, "Stan Hartling"), "stan200x300.jpg")

    def test_photo_above_the_name(self):
        """The layout that caused the mis-assignment.

        Positionally, Stan's portrait falls inside Miles' section and Tom's
        falls inside Stan's — every member would wear the next one's face.
        """
        members = parse_members(BEFORE)
        self.assertEqual(photo_of(members, "Miles Hamm"), "mileshammL.jpg")
        self.assertEqual(photo_of(members, "Stan Hartling"), "stan200x300.jpg")
        self.assertEqual(photo_of(members, "Tom Mothorpe"), "tommothorpeL.jpg")

    def test_both_layouts_on_one_page(self):
        """One site puts the first portrait below the name and the rest above."""
        members = parse_members(AFTER + BEFORE)
        self.assertEqual(photo_of(members, "Charles Edward Dickson"), "charlesdickson2018.jpg")
        self.assertEqual(photo_of(members, "Miles Hamm"), "mileshammL.jpg")
        self.assertEqual(photo_of(members, "Tom Mothorpe"), "tommothorpeL.jpg")

    def test_a_photo_matching_nobody_is_dropped(self):
        """A departed member's portrait is often left behind in the markup.

        The nearest heading must not inherit it — that is a wrong face, which
        reads as true. No photo shows initials, which reads as missing.
        """
        markup = """
        <h3>James D. Stanton</h3>
        <figure><img src="/wp-content/uploads/2018/01/christiandegrace2018.jpg"></figure>
        <p>A long biography sentence about James.</p>
        """
        self.assertEqual(photo_of(parse_members(markup), "James D. Stanton"), "")

    def test_an_unnamed_file_is_dropped(self):
        markup = """
        <h3>Tom McKeown</h3>
        <figure><img src="/wp-content/uploads/2022/07/Screenshot-2022-07-12-103959-1.jpg"></figure>
        <p>A long biography sentence about Tom.</p>
        """
        self.assertEqual(photo_of(parse_members(markup), "Tom McKeown"), "")

    def test_two_members_sharing_a_first_name_are_not_guessed(self):
        """A first name only counts when it belongs to one member on the page."""
        markup = """
        <h3>Tom McKeown</h3>
        <p>A long biography sentence about Tom McKeown.</p>
        <figure><img src="/wp-content/uploads/2016/02/tom-portrait.jpg"></figure>
        <h3>Tom Mothorpe</h3>
        <p>A long biography sentence about Tom Mothorpe.</p>
        """
        members = parse_members(markup)
        self.assertEqual(photo_of(members, "Tom McKeown"), "")
        self.assertEqual(photo_of(members, "Tom Mothorpe"), "")

    def test_a_short_first_name_still_matches_when_unique(self):
        markup = """
        <h3>Wes Stearns</h3>
        <figure><img src="/wp-content/uploads/2021/09/wes-good-front-238x300.jpg"></figure>
        <p>A long biography sentence about Wes.</p>
        """
        self.assertEqual(
            photo_of(parse_members(markup), "Wes Stearns"), "wes-good-front-238x300.jpg"
        )

    def test_a_size_variant_suffix_does_not_defeat_the_match(self):
        markup = """
        <h3>Linda Donavan Harper</h3>
        <figure><img src="/wp-content/uploads/2017/01/harper2017L-238x300.jpg"></figure>
        <p>A long biography sentence about Linda.</p>
        """
        self.assertEqual(
            photo_of(parse_members(markup), "Linda Donavan Harper"), "harper2017L-238x300.jpg"
        )

    def test_an_ambiguous_photo_goes_to_nobody(self):
        """Two people it could belong to means it belongs to neither.

        Declining leaves both showing initials. Splitting the difference would
        put a real face on a 50% chance of being the wrong person.
        """
        markup = """
        <h3>Stan Hartling</h3>
        <figure><img src="/wp-content/uploads/2019/03/stan200x300.jpg"></figure>
        <p>A long biography sentence about Stan.</p>
        <h3>Stan Hartling Jr</h3>
        <p>A long biography sentence about his son.</p>
        """
        self.assertEqual([m["photo"] for m in parse_members(markup)], [None, None])

    def test_no_photo_is_ever_used_twice(self):
        members = parse_members(AFTER + BEFORE)
        used = [m["photo"] for m in members if m["photo"]]
        self.assertEqual(len(used), len(set(used)))
