'''
Copyright (C) 2024-2026 Mo Zhou <lumin@debian.org>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
'''
import pytest
import json
import os
import tempfile
from unittest.mock import patch
from debgpt.cli import main, _resolve_resume_path


@pytest.mark.parametrize('cmd', (
    '-F dryrun',
    '-F dryrun -Hf Makefile',
    '-F dryrun -Qf Makefile',
    '-F dryrun --invalid-argument-example man',
    '-F dryrun --man man',
    '-F dryrun --version',
    '-F dryrun --cmd "man man"',
))
def test_cli_system_exit(cmd: str):
    with pytest.raises(SystemExit):
        main(cmd.split())


def test_cli_backend_routing():
    with patch('debgpt.cli.subcmd_backend') as mock_subcmd:
        mock_subcmd.side_effect = SystemExit(0)
        with pytest.raises(SystemExit):
            main(['backend'])
        mock_subcmd.assert_called_once()


class TestResolveResumePath:
    '''Tests for the _resolve_resume_path helper.'''

    def test_explicit_path(self):
        '''When a path is explicitly given, it is returned directly.'''
        ag = type('ag', (), {
            'json_file_path': '/tmp/some-session.json',
            'debgpt_home': '/tmp',
        })()
        result = _resolve_resume_path(ag)
        assert result == '/tmp/some-session.json'

    def test_no_last_file(self):
        '''When no path and no LAST file, exit(1) is called.'''
        with tempfile.TemporaryDirectory() as tmpdir:
            ag = type('ag', (), {
                'json_file_path': None,
                'debgpt_home': tmpdir,
            })()
            with pytest.raises(SystemExit) as exc_info:
                _resolve_resume_path(ag)
            assert exc_info.value.code == 1

    def test_last_file_points_to_valid_json(self):
        '''LAST file pointing to an existing JSON is resolved correctly.'''
        with tempfile.TemporaryDirectory() as tmpdir:
            # Create a session JSON file
            json_path = os.path.join(tmpdir, 'test-uuid.json')
            with open(json_path, 'wt') as f:
                json.dump([{'role': 'user', 'content': 'hello'}], f)
            # Create LAST pointer
            last_path = os.path.join(tmpdir, 'LAST')
            with open(last_path, 'wt') as f:
                f.write('test-uuid.json\n')
            ag = type('ag', (), {
                'json_file_path': None,
                'debgpt_home': tmpdir,
            })()
            result = _resolve_resume_path(ag)
            assert result == json_path

    def test_last_file_points_to_missing_json(self):
        '''LAST file pointing to a nonexistent JSON exits with error.'''
        with tempfile.TemporaryDirectory() as tmpdir:
            last_path = os.path.join(tmpdir, 'LAST')
            with open(last_path, 'wt') as f:
                f.write('nonexistent.json\n')
            ag = type('ag', (), {
                'json_file_path': None,
                'debgpt_home': tmpdir,
            })()
            with pytest.raises(SystemExit) as exc_info:
                _resolve_resume_path(ag)
            assert exc_info.value.code == 1


class TestResumeSubcommand:
    '''Integration tests for the resume subcommand.'''

    def test_resume_with_explicit_path(self):
        '''resume with a path loads the session and enters interactive mode.'''
        with tempfile.TemporaryDirectory() as tmpdir:
            # Create a session JSON file
            json_path = os.path.join(tmpdir, 'resume-test.json')
            session = [
                {'role': 'system', 'content': 'You are helpful.'},
                {'role': 'user', 'content': 'Hello'},
                {'role': 'assistant', 'content': 'Hi there!'},
            ]
            with open(json_path, 'wt') as f:
                json.dump(session, f)

            # Patch interact_with to avoid blocking
            with patch('debgpt.cli.frontend.interact_with') as mock_interact:
                main(['-F', 'echo', '--debgpt_home', tmpdir,
                      'resume', json_path])
                mock_interact.assert_called_once()

    def test_resume_with_last_file(self):
        '''resume without path uses the LAST file in debgpt_home.'''
        with tempfile.TemporaryDirectory() as tmpdir:
            # Create a session JSON file
            json_path = os.path.join(tmpdir, 'last-session.json')
            session = [
                {'role': 'user', 'content': 'Question'},
                {'role': 'assistant', 'content': 'Answer'},
            ]
            with open(json_path, 'wt') as f:
                json.dump(session, f)
            # Create LAST pointer
            last_path = os.path.join(tmpdir, 'LAST')
            with open(last_path, 'wt') as f:
                f.write('last-session.json\n')

            with patch('debgpt.cli.frontend.interact_with') as mock_interact:
                main(['-F', 'echo', '--debgpt_home', tmpdir, 'resume'])
                mock_interact.assert_called_once()

    def test_resume_no_last_file_exits(self):
        '''resume with no path and no LAST file exits with error.'''
        with tempfile.TemporaryDirectory() as tmpdir:
            with pytest.raises(SystemExit) as exc_info:
                main(['-F', 'echo', '--debgpt_home', tmpdir, 'resume'])
            assert exc_info.value.code == 1
