# BFH Science Self-Service Portal
# Copyright (C) 2025-2026 IKUS Software
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

from unittest import mock

import responses
from parameterized import parameterized
from responses import matchers

from . import WebCase

TICKET_CREATE_URL = 'https://znuny.example.com/otrs/nph-genericinterface.pl/Webservice/rest-api/TicketCreate'


class ComputeHandlerTest(WebCase):

    login = True

    default_config = {
        'znuny-ticket-create-url': TICKET_CREATE_URL,
        'znuny-userlogin': 'myuser',
        'znuny-password': 'test123',
    }

    @parameterized.expand(
        [
            (
                'valid_linux_personal',
                {'server_type': 'linux', 'server_usage': 'user', 'server_user_name': 'unused', 'message': 'N/A'},
                'SSP: LNI Compute - New compute: linux.test-user.bfh.science (linux)',
            ),
            (
                'valid_group',
                {'server_type': 'redis', 'server_usage': 'group', 'server_group_name': 'mygroup', 'message': 'N/A'},
                'SSP: LNI Compute - New compute: redis.mygroup.bfh.science (redis)',
            ),
            (
                'valid_empty_message',
                {'server_type': 'python', 'server_usage': 'group', 'server_group_name': 'mygroup', 'message': ''},
                'SSP: LNI Compute - New compute: python.mygroup.bfh.science (python)',
            ),
            (
                'invalid_group_name',
                {
                    'server_type': 'linux',
                    'server_usage': 'group',
                    'server_group_name': 'invalid.name',
                    'message': 'N/A',
                },
                False,
            ),
            (
                'invalid_server_type',
                {'server_type': 'invalid', 'server_usage': 'group', 'server_group_name': 'mygroup', 'message': 'N/A'},
                False,
            ),
            (
                'invalid_message',
                {
                    'server_type': 'linux',
                    'server_usage': 'group',
                    'server_group_name': 'mygroup',
                    'message': 'too long' * 100,
                },
                False,
            ),
        ]
    )
    def test_request_container(self, name, data, expected_subject):
        # Mock ticket creation.
        self.responses.add(
            responses.POST,
            TICKET_CREATE_URL,
            json={'TicketID': '1234', 'TicketNumber': '0987654321'},
            status=200,
            match=[
                matchers.json_params_matcher(
                    {"Ticket": {"Title": expected_subject, "Service": "LNI Compute"}}, strict_match=False
                )
            ],
        )
        # Given a user
        # When user request a new compute
        self.getPage(
            "/dashboard/request-container",
            body=data,
            method='POST',
        )
        # Then user is redirect
        self.assertStatus(303)
        self.assertHeaderItemValue('Location', f'{self.baseurl}/dashboard')
        # Then an email get send to ITS
        if expected_subject:
            # Then dashboard page show success
            self.getPage("/dashboard/")
            self.assertStatus(200)
            self.assertInBody(
                'Success! Your request has been logged as ticket <a href="https://znuny.example.com/otrs/index.pl?Action=AgentTicketZoom;TicketID=1234" target="_blank">#0987654321</a>. A copy has been emailed to you.'
            )
            # Then ticket creation was send
            self.responses.assert_all_requests_are_fired = True
            # Then email send to the user it self.
            self.listener.send_mail.assert_called_once_with(
                to='test@example.com',
                cc=None,
                reply_to=None,
                subject=f"[Ticket#0987654321] {expected_subject}",
                message=mock.ANY,
            )
        else:
            self.responses.assert_all_requests_are_fired = False
            # Then email are not sent.
            self.assertEqual(self.listener.send_mail.call_count, 0)
            # Then dashboard page show failure
            self.getPage("/dashboard/")
            self.assertStatus(200)
            self.assertNotInBody("Success!")
            self.assertInBody("alert alert-danger")

    def test_compute_json_empty(self):
        # Given a user without data
        # When querying storage list
        self.getJson("/dashboard/compute.json")
        # Then the list is empty.
        self.assertBody('{"data": []}')

    def test_compute_json_with_data(self):
        # Given a user with data
        self.conn.strategy.add_entry(
            'cn=myuser,ou=Staff,ou=Accounts,dc=bfh',
            {
                'userPassword': self.password,
                'uid': ['myuser'],
                'objectClass': ['person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount'],
                'bfhCephDirectory': 'Users/myuser',
                'givenName': ['My'],
                'sn': ['User'],
                'memberOf': [
                    'cn=IDM.perm.compute.dep_some-compute-name.admin,ou=Security,ou=Groups,dc=bfh',
                    'cn=IDM.perm.compute.dep_second-compute-name.users,ou=Security,ou=Groups,dc=bfh',
                ],
            },
        )
        self.conn.strategy.add_entry(
            'cn=amanager,ou=Staff,ou=Accounts,dc=bfh',
            {
                'uid': ['amanager'],
                'objectClass': ['person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount'],
                'bfhCephDirectory': 'Users/amanager',
                'givenName': ['A'],
                'sn': ['Manager'],
                'memberOf': [
                    'cn=IDM.perm.compute.dep_some-compute-name.admin,ou=Security,ou=Groups,dc=bfh',
                ],
            },
        )
        self.conn.strategy.add_entry(
            'cn=secondmanager,ou=Staff,ou=Accounts,dc=bfh',
            {
                'uid': ['secondmanager'],
                'objectClass': ['person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount'],
                'bfhCephDirectory': 'Users/secondmanager',
                'givenName': ['Second'],
                'sn': ['Manager'],
            },
        )
        self.conn.strategy.add_entry(
            'cn=IDM.perm.compute.dep_some-compute-name.admin,ou=Security,ou=Groups,dc=bfh',
            {
                'objectClass': ['group'],
                # Test if multi-value is also working.
                'bfhGroupManager': ['cn=amanager,ou=Staff,ou=Accounts,dc=bfh', 'cn=myuser,ou=Staff,ou=Accounts,dc=bfh'],
            },
        )
        self.conn.strategy.add_entry(
            'cn=IDM.perm.compute.dep_second-compute-name.users,ou=Security,ou=Groups,dc=bfh',
            {
                'objectClass': ['group'],
                'bfhGroupManager': [
                    'cn=secondmanager,ou=Staff,ou=Accounts,dc=bfh, cn=myuser,ou=Staff,ou=Accounts,dc=bfh'
                ],
                'bfhLinuxContainer': ['second-compute-name.dep.bfh.ch'],
            },
        )

        # When querying storage list
        self._login('myuser', self.password)
        data = self.getJson("/dashboard/compute.json")

        # Then list of storage is returned.
        self.assertEqual(
            data,
            {
                'data': [
                    {
                        'name': 'dep_some-compute-name',
                        'permission': 'admin',
                        'usage': 'group',
                        'owners': [
                            {'name': 'A Manager', 'username': 'amanager', 'email': None},
                            {'name': 'My User', 'username': 'myuser', 'email': None},
                        ],
                        'group': 'IDM.perm.compute.dep_some-compute-name.admin',
                        'manage_url': 'https://idm.bfh.ch/group/IDM.perm.compute.dep_some-compute-name.admin',
                        'service': 'LNI Compute',
                    },
                    {
                        'name': 'second-compute-name.dep.bfh.ch',
                        'permission': 'users',
                        'usage': 'group',
                        'owners': [
                            {'name': 'My User', 'username': 'myuser', 'email': None},
                            {'name': 'Second Manager', 'username': 'secondmanager', 'email': None},
                        ],
                        'group': 'IDM.perm.compute.dep_second-compute-name.users',
                        'manage_url': 'https://idm.bfh.ch/group/IDM.perm.compute.dep_second-compute-name.users',
                        'service': 'LNI Compute',
                    },
                ]
            },
        )
