from django.test import TestCase
from django.urls import reverse

from accounts.models import User
from companies.models import Company
from seekers.completion import completion
from seekers.models import (
    Certification, Education, ProfessionalReference, SeekerProfile, SpokenLanguage, WorkExperience,
)

SECTIONS = ('basics', 'about', 'experience', 'education', 'skills', 'preferences', 'cv', 'privacy', 'preview')


class ProfessionalProfileEditorTests(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(username='sk', email='sk@x.com', password='pw12345!', role=User.Role.SEEKER)
        self.profile = SeekerProfile.objects.create(
            user=self.user, slug='sk', full_name='Jane Phiri', headline='Sales Executive', category='Sales',
            category_slug='sales', location='Lusaka')
        self.client.force_login(self.user)
        self.url = reverse('seekers:edit_profile')

    def _post(self, section, data):
        return self.client.post(self.url, {'section': section, **data})

    def _item(self, section, kind, data, action='item_add', **extra):
        return self.client.post(self.url, {'section': section, 'kind': kind, 'action': action,
                                           **{f'{kind}{extra.get("pk", "new")}-{k}': v for k, v in data.items()},
                                           **({'item': extra['pk']} if 'pk' in extra else {})})

    def test_every_section_renders(self):
        for section in SECTIONS:
            self.assertEqual(self.client.get(self.url, {'section': section}).status_code, 200, section)

    def test_employer_cannot_open_it(self):
        emp = User.objects.create_user(username='e', email='e@x.com', password='pw12345!', role=User.Role.COMPANY)
        self.client.force_login(emp)
        self.assertNotEqual(self.client.get(self.url).status_code, 200)

    def test_account_without_profile_gets_one(self):
        other = User.objects.create_user(username='n', email='n@x.com', password='pw12345!', role=User.Role.SEEKER)
        self.client.force_login(other)
        self.assertEqual(self.client.get(self.url).status_code, 200)
        self.assertTrue(SeekerProfile.objects.filter(user=other).exists())

    def test_basics_saves_name_location_and_years(self):
        r = self._post('basics', {'first_name': 'Janet', 'last_name': 'Phiri Banda', 'headline': 'Sales Manager',
                                  'city': 'Kitwe', 'country': 'Zambia', 'industry': 'Retail & Wholesale', 'years_experience': '8',
                                  'professional_status': 'employed', 'show_photo': 'on'})
        self.assertEqual(r.status_code, 302)
        self.profile.refresh_from_db()
        self.assertEqual((self.profile.full_name, self.profile.location, self.profile.years_experience),
                         ('Janet Phiri Banda', 'Kitwe', 8))
        self.assertEqual(self.profile.industry, 'Retail & Wholesale')

    def test_changing_industry_and_sub_industry_together_in_one_save(self):
        r = self._post('basics', {'first_name': 'Jane', 'headline': 'Sales Executive', 'city': 'Lusaka',
                                  'country': 'Zambia', 'industry': 'Information Technology & Software',
                                  'sub_industry': 'IT Services', 'years_experience': '5'})
        self.assertEqual(r.status_code, 302, r.context['form'].errors if r.status_code == 200 else None)
        self.profile.refresh_from_db()
        self.assertEqual((self.profile.industry, self.profile.sub_industry), ('Information Technology & Software', 'IT Services'))

    def test_about_requires_summary(self):
        self.assertEqual(self._post('about', {'bio': ''}).status_code, 200)
        self._post('about', {'bio': 'Experienced seller.', 'products_experience': 'Beverages\nSeeds'})
        self.profile.refresh_from_db()
        self.assertEqual(self.profile.product_list, ['Beverages', 'Seeds'])

    def test_save_and_continue_skips_already_finished_sections(self):
        # 'about' and 'experience' are already complete; saving 'basics' should jump
        # past both to the next unfinished section, not just the next in order.
        self.profile.bio = 'A' * 60
        self.profile.save()
        WorkExperience.objects.create(seeker=self.profile, company='Z', title='T', start_year=2018, is_current=True)
        r = self._post('basics', {'first_name': 'Jane', 'headline': 'Sales Executive', 'city': 'Lusaka',
                                  'country': 'Zambia', 'years_experience': '5', 'then': 'next'})
        self.assertNotIn('section=about', r['Location'])
        self.assertNotIn('section=experience', r['Location'])
        self.assertIn('section=education', r['Location'])

    def test_skills_saved(self):
        self._post('skills', {'skills': 'Negotiation\nLeadership'})
        self.profile.refresh_from_db()
        self.assertEqual(self.profile.skill_list, ['Negotiation', 'Leadership'])

    def test_experience_add_update_delete_and_sync(self):
        self._item('experience', 'experience', {'company': 'Zambeef', 'title': 'Sales Manager', 'start_year': '2018',
                                                'is_current': 'on', 'responsibilities': 'Led a team of 8.'})
        exp = WorkExperience.objects.get()
        self.assertEqual(exp.seeker, self.profile)
        self.profile.refresh_from_db()
        self.assertIn('Sales Manager at Zambeef', self.profile.experience_summary)
        self.assertEqual(self.profile.current_employer, 'Zambeef')
        self._item('experience', 'experience', {'company': 'Zambeef Products', 'title': 'Sales Manager', 'start_year': '2018',
                                                'is_current': 'on'}, action='item_update', pk=exp.pk)
        exp.refresh_from_db()
        self.assertEqual(exp.company, 'Zambeef Products')
        self.client.post(self.url, {'section': 'experience', 'kind': 'experience', 'action': 'item_delete', 'item': exp.pk})
        self.assertFalse(WorkExperience.objects.exists())

    def test_experience_needs_end_year_unless_current(self):
        r = self._item('experience', 'experience', {'company': 'A', 'title': 'B', 'start_year': '2018'})
        self.assertEqual(r.status_code, 200)
        self.assertFalse(WorkExperience.objects.exists())
        self.assertContains(r, 'tick')

    def test_other_users_items_are_untouchable(self):
        other = User.objects.create_user(username='o', email='o@x.com', password='pw12345!', role=User.Role.SEEKER)
        op = SeekerProfile.objects.create(user=other, slug='o', full_name='Other Person', headline='x', category='x', location='x')
        cert = Certification.objects.create(seeker=op, name='CPA')
        r = self.client.post(self.url, {'section': 'education', 'kind': 'certification', 'action': 'item_delete', 'item': cert.pk})
        self.assertEqual(r.status_code, 404)
        self.assertTrue(Certification.objects.filter(pk=cert.pk).exists())

    def test_education_language_certification_and_reference(self):
        self._item('education', 'education', {'institution': 'UNZA', 'qualification': 'BCom', 'start_year': '2010', 'end_year': '2014'})
        self._item('education', 'certification', {'name': 'ACCA', 'issuer': 'ACCA UK'})
        self._item('skills', 'language', {'language': 'Bemba', 'proficiency': 'native'})
        self._item('privacy', 'reference', {'name': 'Boss Man', 'email': 'boss@x.com'})
        self.assertEqual(Education.objects.count(), 1)
        self.assertEqual(Certification.objects.count(), 1)
        self.assertEqual(SpokenLanguage.objects.get().summary_line, 'Bemba (Native)')
        self.assertEqual(ProfessionalReference.objects.count(), 1)
        self.profile.refresh_from_db()
        self.assertIn('BCom, UNZA', self.profile.education)

    def test_education_end_before_start_rejected(self):
        r = self._item('education', 'education', {'institution': 'U', 'qualification': 'Q', 'start_year': '2014', 'end_year': '2010'})
        self.assertFalse(Education.objects.exists())
        self.assertEqual(r.status_code, 200)

    def test_preferences_saved_and_validated(self):
        r = self._post('preferences', {'target_titles': 'Sales Manager', 'employment_options': ['Full-Time', 'Contract'],
                                       'arrangement_options': ['Hybrid'], 'availability': 'active', 'availability_timeline': '1m',
                                       'salary_min': '15000', 'salary_max': '20000', 'salary_currency': 'ZMW',
                                       'authorised_countries': 'Zambia', 'authorisation_options': ['I am eligible to work in Zambia']})
        self.assertEqual(r.status_code, 302)
        self.profile.refresh_from_db()
        self.assertEqual(self.profile.employment_type_list, ['Full-Time', 'Contract'])
        self.assertEqual(self.profile.work_authorisation_list, ['I am eligible to work in Zambia'])
        bad = self._post('preferences', {'availability': 'active', 'salary_min': '20000', 'salary_max': '10000', 'salary_currency': 'ZMW'})
        self.assertEqual(bad.status_code, 200)

    def test_specific_date_requires_date(self):
        r = self._post('preferences', {'availability': 'active', 'availability_timeline': 'date', 'salary_currency': 'ZMW'})
        self.assertEqual(r.status_code, 200)

    def test_privacy_visibility_and_contact(self):
        self._post('privacy', {'phone': '+260977000000', 'visibility': 'private', 'contact_visibility': 'nobody', 'confirm_accuracy': 'on'})
        self.profile.refresh_from_db(); self.user.refresh_from_db()
        self.assertFalse(self.profile.is_public)
        self.assertFalse(self.profile.contact_employers or self.profile.contact_team)
        self.assertEqual(self.user.phone, '+260977000000')
        self.assertTrue(self.profile.confirm_accuracy)

    def test_recruiters_only_profile_hidden_from_public_but_open_to_employers(self):
        self.profile.visibility = 'recruiters'
        self.profile.save()
        detail = reverse('seekers:detail', args=[self.profile.slug])
        self.client.logout()
        self.assertEqual(self.client.get(detail).status_code, 404)
        emp = User.objects.create_user(username='emp', email='emp@x.com', password='pw12345!', role=User.Role.COMPANY)
        Company.objects.create(name='Acme', slug='acme', initials='A', industry='Retail', location='L', description='d', owner=emp)
        self.client.force_login(emp)
        self.assertEqual(self.client.get(detail).status_code, 200)

    def test_references_never_public(self):
        ProfessionalReference.objects.create(seeker=self.profile, name='Secret Referee', email='ref@x.com')
        self.assertNotContains(self.client.get(reverse('seekers:detail', args=[self.profile.slug])), 'Secret Referee')

    def test_public_profile_shows_structured_sections_to_owner(self):
        WorkExperience.objects.create(seeker=self.profile, company='Zambeef', title='Sales Manager', start_year=2018, is_current=True,
                                      responsibilities='Led a team.')
        Certification.objects.create(seeker=self.profile, name='ACCA')
        page = self.client.get(reverse('seekers:detail', args=[self.profile.slug]))
        for text in ('Zambeef', 'Led a team.', 'ACCA'):
            self.assertContains(page, text)

    def test_completion_grows(self):
        before = completion(self.profile)['percent']
        WorkExperience.objects.create(seeker=self.profile, company='Z', title='T', start_year=2018, is_current=True)
        self.profile.skills = 'A\nB\nC'
        self.profile.save()
        self.assertGreater(completion(self.profile)['percent'], before)

    def test_profile_items_feed_ats_text(self):
        from ats.services import _profile_item_text
        WorkExperience.objects.create(seeker=self.profile, company='Zambeef', title='Sales Manager', start_year=2018,
                                      is_current=True, responsibilities='Key account management')
        self.assertIn('Key account management', ' '.join(_profile_item_text(self.profile)))
