# Part of Odoo. See LICENSE file for full copyright and licensing details.

from datetime import date, timedelta

from freezegun import freeze_time

from odoo import Command
from odoo.tests import users
from odoo.tests.common import HttpCase, new_test_user
from odoo.addons.mail.tests.common import MailCommon


class TestAvatarCardTour(MailCommon, HttpCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        # Freeze on a fixed mid-week day so the time off below (created relative
        # to "today") always ends on a working day. When it ends on a Sat/Sun
        # its date_to is the weekend's 00:00, so the "currently on leave" window
        # closes at midnight and the avatar card's out-of-office indicator flakes
        # away once the run crosses it (runbot 242512).
        cls.startClassPatcher(freeze_time("2024-06-12"))
        new_test_user(
            cls.env,
            login="hr_user",
            company_ids=[Command.link(cls.env.company.id), Command.link(cls.company_2.id)],
            groups="hr.group_hr_user",
        )

        # hr setup for multi-company
        department = (
            cls.env["hr.department"]
            .with_company(cls.company_2)
            .create({"name": "Test Department", "company_id": cls.company_2.id})
        )
        job = (
            cls.env["hr.job"]
            .with_company(cls.company_2)
            .create({"name": "Test Job Title", "company_id": cls.company_2.id})
        )
        other_partner = (
            cls.env["res.partner"]
            .with_company(cls.company_2)
            .create({
                "name": "Test Other Partner",
                "company_id": cls.company_2.id,
                "phone": "987654321",
            })
        )
        test_employee = (
            cls.env["hr.employee"]
            .with_company(cls.company_2)
            .create({
                "name": "Test Employee",
                "user_id": cls.user_employee_c2.id,
                "company_id": cls.company_2.id,
                "department_id": department.id,
                "job_id": job.id,
                "address_id": other_partner.id,
                "work_email": "test_employee@test.com",
                "work_phone": "123456789",
            })
        )
        cls.test_employee = test_employee
        cls.user_employee_c2.write({"employee_ids": [Command.link(test_employee.id)]})
        new_test_user(
            cls.env,
            login="base_user",
            company_ids=[Command.link(cls.env.company.id), Command.link(cls.company_2.id)],
        )

        # hr_holidays setup for multi-company
        work_entry_type = (
            cls.env['hr.work.entry.type']
            .with_company(cls.company_2)
            .create(
                {
                    "name": "Time Off multi company",
                    "code": "TOMULTI",
                    "count_as": "absence",
                    "requires_allocation": False,
                    'request_unit': 'day',
                    'unit_of_measure': 'day',
                }
            )
        )
        cls.env["hr.leave"].with_company(cls.company_2).with_context(
            leave_skip_state_check=True
        ).create(
            {
                "name": "Test Leave",
                "company_id": cls.company_2.id,
                "work_entry_type_id": work_entry_type.id,
                "employee_id": cls.test_employee.id,
                "request_date_from": (date.today() - timedelta(days=1)),
                "request_date_to": (date.today() + timedelta(days=1)),
                "state": "validate",
            }
        )
        cls.test_record = cls.env["hr.department"].create(
            [
                {"name": "Test", "company_id": cls.env.company.id},
                {"name": "Test 2", "company_id": cls.env.company.id},
                {"name": "Test 3", "company_id": cls.company_2.id},
            ]
        )

    def _setup_channel(self, user):
        # Clear the user's pre-existing (demo) activities so the systray counter
        # snapshot computed at page load reflects only this test's activities.
        self.env["mail.activity"].with_user(user).search([("user_id", "=", user.id)]).unlink()
        self.user_employee_c2.partner_id.sudo().with_user(self.user_employee_c2).message_post(
            body="Test message in chatter",
            message_type="comment",
            subtype_xmlid="mail.mt_comment",
        )
        activity_type_todo = "mail.mail_activity_data_todo"
        # Deadline in the past: the counter only counts today and overdue activities, and
        # the default deadline (today in the scheduling env's timezone, Europe/Brussels
        # for the superuser with demo data) is tomorrow for a user without timezone (UTC
        # fallback) when the test runs between 22:00 and 00:00 UTC, making the activities
        # planned and the counter empty (runbot 941407). A week-old deadline is overdue
        # in every timezone.
        date_deadline = date.today() - timedelta(days=7)
        self.test_record[0].activity_schedule(
            activity_type_todo,
            date_deadline,
            summary="Test Activity for Company 2",
            user_id=user.id,
        )
        self.test_record[1].activity_schedule(
            activity_type_todo,
            date_deadline,
            summary="Another Test Activity for Company 2",
            user_id=user.id,
        )
        self.test_record[2].activity_schedule(
            activity_type_todo,
            date_deadline,
            summary="Test Activity for Company 3",
            user_id=user.id,
        )
        # The unlink/schedule above emit "mail.activity/updated"; drop those bus rows so the
        # systray counter baseline (activity_counter_bus_id, captured at page load) starts
        # clean and none of them lands after it and gets double-counted (runbot 237779).
        self._reset_bus()

    @users("admin", "hr_user")
    def test_avatar_card_tour_multi_company(self):
        self._setup_channel(self.env.user)
        self.start_tour(
            f"/odoo/res.partner/{self.user_employee_c2.partner_id.id}",
            "avatar_card_tour",
            login=self.env.user.login,
        )

    @users("base_user")
    def test_avatar_card_tour_multi_company_no_hr_access(self):
        self._setup_channel(self.env.user)
        self.start_tour(
            f"/odoo/res.partner/{self.user_employee_c2.partner_id.id}",
            "avatar_card_tour_no_hr_access",
            login=self.env.user.login,
        )

    @users("employee")
    def test_get_employee_data_from_inaccessible_company(self):
        self.authenticate(self.env.user.login, self.env.user.login)
        channel = self.env["discuss.channel"]._get_or_create_chat(self.user_employee_c2.partner_id.id)
        members_data = self.make_jsonrpc_request(
            "/discuss/channel/members",
            {"channel_id": channel.id, "known_member_ids": []},
        )
        avatar_card_data = self.make_jsonrpc_request(
            "/mail/data",
            {"fetch_params": [["avatar_card", {"id": self.user_employee_c2.id, "model": "res.users"}]]},
        )
        members_user = next(
            user for user in members_data["res.users"] if user["id"] == self.user_employee_c2.id
        )
        avatar_card_user = next(
            user for user in avatar_card_data["res.users"] if user["id"] == self.user_employee_c2.id
        )
        self.assertIn(
            self.test_employee.id,
            [employee["id"] for employee in members_data["hr.employee"]],
        )
        self.assertIn(
            self.test_employee.id,
            [employee["id"] for employee in avatar_card_data["hr.employee"]],
        )
        self.assertEqual(members_user["all_employee_ids"], [self.test_employee.id])
        self.assertEqual(avatar_card_user["all_employee_ids"], [self.test_employee.id])
