#
# <one line to give the program's name and a brief idea of what it does.>
# SPDX-FileCopyrightText: 2022 gothic <email>
# SPDX-License-Identifier: GPL-3.0-or-later
#

from csharp_dao import cloudServiceDAO_pb2_grpc, cloudServiceDAO_pb2
from python_fortanix import fortanix_pb2_grpc as pb2_grpc, fortanix_pb2 as pb2
from flask import jsonify
import grpc
import base64
import json
import re
import uuid

from datetime import datetime

from google.protobuf.json_format import MessageToJson

class SingletonMeta(type):
  _instances = {}

  def __call__(cls, *args, **kwargs):
    if cls not in cls._instances:
      instance = super().__call__(*args, **kwargs)
      cls._instances[cls] = instance
    return cls._instances[cls]


class Fortanix(metaclass=SingletonMeta):
  
  HOST_SRV_FRTNX = "fortanix-consumer-python-grpc-svc:8448"
  HOST_SRV_DAO = "dao-csharp-grpc-svc:8445"

  _message_success = ""
  _path_app = ""
  _request = {}
  _action = ""

  def __init__(self, request: dict, PATH_APP: str, action: str) -> None:
    self._path_app = PATH_APP
    self._request = request
    self._action = action

  # def main(request, PATH_APP, action):
  def main(self):
    try:
      if(self._action=='add'):
        self._add_srv()
      else:
        raise Exception(f"No {self._action} es una opción valida.")

    except Exception as e:
      return {
        "message": f"Ocurrio un error: {e}",
        "valid": False,
        "class": "alert-danger"
      }
    else: 
      return {
        "message": f"Se ejecuta satisfactoriamente: {self._message_success}",
        "valid": True,
        "class": "alert-danger"
      }
    
  def _add_srv(self):
    # print(self._request.json)
    # data_form = (base64.b64decode(request.form['data_form_config_r']) if len(request.form.getlist('data_form_config_r')) > 0 else 'NOTFOUND')
    data_form = (json.loads(base64.b64decode(self._request.json['data_form_config_r'])) if "data_form_config_r" in self._request.json else 'NOTFOUND')
    email = data_form["email_fortanix"]
    tenant_vcloud = (self._request.json["tenant_vcloud"] if "tenant_vcloud" in self._request.json else 'NOTFOUND')
    user_vcloud = (self._request.json["user_vcloud"] if "user_vcloud" in self._request.json else 'NOTFOUND')
    plan_id = (int(self._request.json['plan_id']) if "plan_id" in self._request.json else 'NOTFOUND')
    user_id = (int(self._request.json['user_id']) if "user_id" in self._request.json else 'NOTFOUND')
   
    rslt_crt_sbscrptn = self._clnt_frtnx_crt_sbscrptn(email, tenant_vcloud, self._credentials_srvfrtnx())
    
    if not (self._is_uuid(rslt_crt_sbscrptn["account_uid"])):
      cadena_json = json.dumps(rslt_crt_sbscrptn)
      crdntls_dao = self._credentials_dao()
      id_cntrctd_srvcs = self._save_contracted_services(crdntls_dao, user_id, plan_id)

      self._message_success = f"El ID DE SERVICES CONTRACTED ES {id_cntrctd_srvcs}"
      
    else:
      raise Exception(f"No se genero la subscripcion en el servicio de fortanix, por que no devolvio un uuid valido: '"+ rslt_crt_sbscrptn["account_uid"] +"'")
    # Fortanix._message_success = "ES UNA PRUEBA"
    # #Fortanix.save_subscription(rslt_clnt_frtnx, user_vcloud, plan_id, Fortanix.credentials_dao(PATH_APP))
    # return {
    #   "message": "Se genero satisfactoriamente el acceso al portal, se le hara llegar un correo con la invitacion.",
    #   "valid": True,
    #   "class": "alert-success"
    # }
    # Fortanix._message_success = f"El user ES {type(rslt_clnt_frtnx)}"
  
  def _credentials_dao(self):
    with open(self._path_app + "/App/certs/csharp_dao/" +"ca.pem", "rb") as fp:
      ca_cert = fp.read()
    creds = grpc.ssl_channel_credentials(ca_cert)
    core_channel = grpc.secure_channel(Fortanix.HOST_SRV_DAO, creds)
    return core_channel
  
  def _save_contracted_services(self, crdntls_dao, userid, planid):
    # stub_dao = cloudServiceDAO_pb2_grpc.servicioDAOServiceStub(crdntls_dao)
    # req_cntrctd_srvc = cloudServiceDAO_pb2.SetContractedServicesRequest(
    #   user_id=userid,
    #   plan_id=planid
    # )
    # rslt_rqust = stub_dao.setContractedServicesService(req_cntrctd_srvc)

    rslt_rspns = "[{\"id\":305}]" 
    # rslt_rspns = rslt_rqust.response.response

    try: # Intentar convertir la cadena JSON 
      object_last_id = json.loads(rslt_rspns)
      return object_last_id[0]["id"]
    except json.JSONDecodeError as e:
      raise Exception(f"No se pudo convertir a json o no devolvio ningún dato valido: {e} : {rslt_rspns}.")
  
  def _save_requests_queue(data_form, user_vcd, plan_id):
    # stub_usr = cloudServiceDAO_pb2_grpc.servicioDAOServiceStub(core_channel)
    # req_usr = cloudServiceDAO_pb2.GetUserVCDRequest(user_name=user_vcd)
    # res_usr = stub_usr.getUserVCD(req_usr)
    # reusr = json.loads(MessageToJson(res_usr))
    # print(reusr)
    # print(type(reusr))
    # id_usr_vcd = reusr["users"][0]["userVCDId"]

    # req_srv_contract = cloudServiceDAO_pb2.SetContractedServicesRequest(
    #   backup_scheduled_id=0,
    #   firewall_id=0,
    #   plan_id=int(plan_id),
    #   user_id=int(id_usr_vcd),
    # )
    # res_srv_contract = stub_usr.GetContractedServicesRequest(req_srv_contract)
    print(res_srv_contract)

  def _credentials_srvfrtnx(self):
    with open(self._path_app + "/App/certs/python_fortanix/" +"ca.pem", "rb") as fp:
      ca_cert = fp.read()
    recommendations_channel = grpc.secure_channel(
      self.HOST_SRV_FRTNX, grpc.ssl_channel_credentials(ca_cert)
    )
    return recommendations_channel
  
  def _clnt_frtnx_crt_sbscrptn(self, email, tenant, credentials):
    return {
      "account_uid": "acct.id", 
      "account_role_uid": "acct_role.id", 
      "account_group_uid": "group.id", 
      "account_group_role_uid": "group_role.id", 
      "account_user_uid": "user.id",
      "supply_datetime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
      "email": email,
      "apps": {}
    }
    client = pb2_grpc.ConsumerStub(credentials)
    request = pb2.AccountToCreate(acct_name=tenant)
    response = client.CreateAccount(request)
    acct = response.res[0]
    request_role = pb2.RoleToCreate(role_name="Account Role",role_desc="Default Role",acct_id=acct.id)
    response_role = client.CreateAccountRole(request_role)
    acct_role = response_role.res[0]
    request_group = pb2.GroupToCreate(group_name="Apps Container",group_desc="Apps",acct_id=acct.id)
    response_group = client.CreateGroup(request_group)
    group = response_group.res[0]
    request_grole = pb2.RoleToCreate(role_name="App Auditor",role_desc="Group Role",acct_id=acct.id)
    response_grole = client.CreateGroupRole(request_grole)
    group_role = response_grole.res[0]
    request_user = pb2.UserToCreate(mail=email,group_id=group.id,group_role=group_role.id,acct_id=acct.id,acct_role=acct_role.id)
    response_user = client.CreateUser(request_user)
    user = response_user.res[0]
    return {
      "account_uid": acct.id, 
      "account_role_uid": acct_role.id, 
      "account_group_uid": group.id, 
      "account_group_role_uid": group_role.id, 
      "account_user_uid": user.id
    }
  
  def _is_uuid(self, cadena):
    try:
      uuid.UUID(cadena, version=4)
      return True
    except ValueError:
      return False
