#!/usr/bin/env python3
#
# Copyright 2024 Acme Gating, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import sys
import json
import requests
import argparse

BREAK = '------------------------------------------------------------'


class Gerrit:
    def __init__(self, url, username, password):
        if url.endswith('/'):
            url = url[:-1]
        self.url = url
        self.session = requests.Session()
        self.session.auth = requests.auth.HTTPBasicAuth(username, password)

    def get(self, path):
        url = f'{self.url}{path}'
        r = self.session.get(url,
                             headers={'Accept': 'application/json',
                                      'Accept-Encoding': 'gzip'})
        if r.status_code == 200:
            ret = json.loads(r.text[4:])
            return ret

    def post(self, path, data):
        url = f'{self.url}{path}'
        r = self.session.post(
            url,
            data=json.dumps(data).encode('utf8'),
            headers={'Content-Type': 'application/json;charset=UTF-8'})
        if r.status_code > 400:
            raise Exception("POST to %s failed with http code %s (%s)",
                            path, r.status_code, r.text)
        if r.text and len(r.text) > 4:
            return json.loads(r.text[4:])

    def list_messages(self, change):
        data = self.get(f'/a/changes/{change}/messages')
        for msg in data:
            name = msg['author'].get('name')
            username = msg['author'].get('username')
            email = msg['author'].get('email')
            date = msg['date']
            msgid = msg['id']
            print(BREAK)
            print(f'Id    : {msgid}')
            print(f'Author: {name} ({username}) <{email}>')
            print(f'Date  : {date}')
            print(msg['message'])

    def delete_message(self, change, message_id, reason):
        self.post(
            f'/a/changes/{change}/messages/{message_id}/delete',
            {'reason': reason})
        print("Deleted")

    def list_comments(self, change, revision):
        data = self.get(f'/a/changes/{change}/revisions/{revision}/comments')
        for path, comments in data.items():
            for msg in comments:
                name = msg['author'].get('name')
                username = msg['author'].get('username')
                email = msg['author'].get('email')
                line = msg.get('line')
                msgid = msg['id']
                print(BREAK)
                print(f'Id    : {msgid}')
                print(f'Author: {name} ({username}) <{email}>')
                print(f'File  : {path} line {line}')
                print(msg['message'])

    def delete_comment(self, change, revision, comment_id, reason):
        self.post(
            f'/a/changes/{change}/revisions/{revision}/'
            f'comments/{comment_id}/delete',
            {'reason': reason})
        print("Deleted")


class App:
    def __init__(self):
        self.parser = argparse.ArgumentParser()
        p = self.parser
        p.add_argument('url',
                       help='Gerrit HTTP url')
        p.add_argument('username',
                       help='Username of Gerrit administrator')
        p.add_argument('password',
                       help='Password of Gerrit administrator')
        subparsers = p.add_subparsers(title='commands',
                                      help='valid commands')

        cmd_list_messages = subparsers.add_parser(
            'list-messages', help='List change messages')
        cmd_list_messages.add_argument('change',
                                       help='Change number')
        cmd_list_messages.set_defaults(func=self.list_messages)

        cmd_delete_message = subparsers.add_parser(
            'delete-message', help='Delete change message')
        cmd_delete_message.add_argument('change',
                                        help='Change number')
        cmd_delete_message.add_argument('message_id',
                                        help='Message ID')
        cmd_delete_message.add_argument(
            'reason',
            help='Reason for removal (will replace message)')
        cmd_delete_message.set_defaults(func=self.delete_message)

        cmd_list_comments = subparsers.add_parser(
            'list-comments', help='List change comments')
        cmd_list_comments.add_argument('change',
                                       help='Change number')
        cmd_list_comments.add_argument('revision',
                                       help='Change revision')
        cmd_list_comments.set_defaults(func=self.list_comments)

        cmd_delete_comment = subparsers.add_parser(
            'delete-comment', help='Delete change comment')
        cmd_delete_comment.add_argument('change',
                                        help='Change number')
        cmd_delete_comment.add_argument('revision',
                                        help='Change revision')
        cmd_delete_comment.add_argument('comment_id',
                                        help='Comment ID')
        cmd_delete_comment.add_argument(
            'reason',
            help='Reason for removal (will replace comment)')
        cmd_delete_comment.set_defaults(func=self.delete_comment)

        args = p.parse_args()
        self.args = args
        self.gerrit = Gerrit(args.url, args.username, args.password)
        if 'func' not in args:
            p.print_help()
            sys.exit(1)
        args.func()

    def list_messages(self):
        self.gerrit.list_messages(self.args.change)

    def delete_message(self):
        self.gerrit.delete_message(self.args.change,
                                   self.args.message_id, self.args.reason)

    def list_comments(self):
        self.gerrit.list_comments(self.args.change, self.args.revision)

    def delete_comment(self):
        self.gerrit.delete_comment(self.args.change, self.args.revision,
                                   self.args.comment_id, self.args.reason)


if __name__ == '__main__':
    App()