from flask_restful import Resource, request, current_app
from schematics.exceptions import DataError
import threading

from backend.models.dtos.message_dto import MessageDTO
from backend.services.team_service import TeamService, NotFound, TeamJoinNotAllowed
from backend.services.users.authentication_service import token_auth, tm
from backend.models.postgis.user import User


class TeamsActionsJoinAPI(Resource):
    @tm.pm_only(False)
    @token_auth.login_required
    def post(self, team_id):
        """
        Request to join a team
        ---
        tags:
          - teams
        produces:
          - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: team_id
              in: path
              description: Unique team ID
              required: true
              type: integer
              default: 1
            - in: body
              name: body
              required: true
              description: JSON object to join team
              schema:
                properties:
                    username:
                        type: string
                        required: true
                    role:
                        type: string
                        required: false
        responses:
            200:
                description: Member added
            403:
                description: Forbidden
            404:
                description: Not found
            500:
                description: Internal Server Error
        """
        try:
            post_data = request.get_json(force=True)
            username = post_data["username"]
            role = post_data.get("role", None)
        except (DataError, KeyError) as e:
            current_app.logger.error(f"error validating request: {str(e)}")
            return str(e), 400

        try:
            authenticated_user_id = token_auth.current_user()
            TeamService.join_team(team_id, authenticated_user_id, username, role)
            if TeamService.is_user_team_manager(team_id, authenticated_user_id):
                return {"Success": "User added to the team"}, 200
            else:
                return {"Success": "Request to join the team sent successfully."}, 200
        except TeamJoinNotAllowed as e:
            return {"Error": str(e)}, 403
        except Exception as e:
            error_msg = f"User POST - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": error_msg}, 500

    @tm.pm_only(False)
    @token_auth.login_required
    def patch(self, team_id):
        """
        Take action on a team invite
        ---
        tags:
          - teams
        produces:
          - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: team_id
              in: path
              description: Unique team ID
              required: true
              type: integer
              default: 1
            - in: body
              name: body
              required: true
              description: JSON object to accept or reject a request to join team
              schema:
                properties:
                    username:
                        type: string
                        required: true
                    type:
                        type: string
                        default: join-response
                        required: true
                    role:
                        type: string
                        default: member
                        required: false
                    action:
                        type: string
                        default: accept
                        required: true
        responses:
            200:
                description: Member added
            403:
                description: Forbidden
            404:
                description: Not found
            500:
                description: Internal Server Error
        """
        try:
            json_data = request.get_json(force=True)
            username = json_data["username"]
            request_type = json_data.get("type", "join-response")
            action = json_data["action"]
            role = json_data.get("role", "member")
        except DataError as e:
            current_app.logger.error(f"error validating request: {str(e)}")
            return str(e), 400

        try:
            authenticated_user_id = token_auth.current_user()
            if request_type == "join-response":
                if TeamService.is_user_team_manager(team_id, authenticated_user_id):
                    TeamService.accept_reject_join_request(
                        team_id, authenticated_user_id, username, role, action
                    )
                    return {"Success": "True"}, 200
                else:
                    return (
                        {
                            "Error": "You don't have permissions to approve this join team request"
                        },
                        403,
                    )
            elif request_type == "invite-response":
                TeamService.accept_reject_invitation_request(
                    team_id, authenticated_user_id, username, role, action
                )
                return {"Success": "True"}, 200
        except Exception as e:
            error_msg = f"Team Join PUT - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": error_msg}, 500


class TeamsActionsLeaveAPI(Resource):
    @tm.pm_only(False)
    @token_auth.login_required
    def post(self, team_id):
        """
        Removes a user from a team
        ---
        tags:
          - teams
        produces:
          - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: team_id
              in: path
              description: Unique team ID
              required: true
              type: integer
              default: 1
            - in: body
              name: body
              required: true
              description: JSON object to remove user from team
              schema:
                properties:
                    username:
                        type: string
                        default: 1
                        required: true
        responses:
            200:
                description: Member deleted
            403:
                description: Forbidden, if user attempting to ready other messages
            404:
                description: Not found
            500:
                description: Internal Server Error
        """
        try:
            authenticated_user_id = token_auth.current_user()
            username = request.get_json(force=True)["username"]
            request_user = User.get_by_id(authenticated_user_id)
            if (
                TeamService.is_user_team_manager(team_id, authenticated_user_id)
                or request_user.username == username
            ):
                TeamService.leave_team(team_id, username)
                return {"Success": "User removed from the team"}, 200
            else:
                return (
                    {
                        "Error": "You don't have permissions to remove {} from this team.".format(
                            username
                        )
                    },
                    403,
                )
        except NotFound:
            return {"Error": "No team member found"}, 404
        except Exception as e:
            error_msg = f"TeamMembers DELETE - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": error_msg}, 500


class TeamsActionsMessageMembersAPI(Resource):
    @token_auth.login_required
    def post(self, team_id):
        """
        Message all team members
        ---
        tags:
          - teams
        produces:
          - application/json
        parameters:
            - in: header
              name: Authorization
              description: Base64 encoded session token
              required: true
              type: string
              default: Token sessionTokenHere==
            - name: team_id
              in: path
              description: Unique team ID
              required: true
              type: integer
              default: 1
            - in: body
              name: body
              required: true
              description: JSON object for creating message
              schema:
                properties:
                    subject:
                        type: string
                        default: Thanks
                        required: true
                    message:
                        type: string
                        default: Thanks for your contribution
                        required: true
        responses:
            200:
                description: Message sent successfully
            401:
                description: Unauthorized - Invalid credentials
            403:
                description: Forbidden
            500:
                description: Internal Server Error
        """
        try:
            authenticated_user_id = token_auth.current_user()
            message_dto = MessageDTO(request.get_json())
            # Validate if team is present
            try:
                team = TeamService.get_team_by_id(team_id)
            except NotFound:
                return {"Error": "Team not found"}, 404

            is_manager = TeamService.is_user_team_manager(
                team_id, authenticated_user_id
            )
            if not is_manager:
                raise ValueError
            message_dto.from_user_id = authenticated_user_id
            message_dto.validate()
            if not message_dto.message.strip() or not message_dto.subject.strip():
                raise DataError({"Validation": "Empty message not allowed"})
        except DataError as e:
            current_app.logger.error(f"Error validating request: {str(e)}")
            return {"Error": "Request payload did not match validation"}, 400
        except ValueError:
            return {"Error": "Unauthorised to send message to team members"}, 403

        try:
            threading.Thread(
                target=TeamService.send_message_to_all_team_members,
                args=(team_id, team.name, message_dto),
            ).start()

            return {"Success": "Message sent successfully"}, 200
        except ValueError as e:
            return {"Error": str(e)}, 403
        except Exception as e:
            error_msg = f"Send message all - unhandled error: {str(e)}"
            current_app.logger.critical(error_msg)
            return {"Error": "Unable to send messages to team members"}, 500
