import requests
import json
import time
import cluster_common
from requests_scripts.requests_helper import *

def get_req_url(host, port):
    return 'http://%s:%s/HttpService/Emit' % (host, port)

def get_clustermgr_requrl(jscfg):
    metaconn = cluster_common.get_metamaster_conn(jscfg)
    rec = get_clustermgr_source(metaconn)
    url = get_req_url(rec['hostaddr'], rec['port'])
    metaconn.close()
    return url

def get_reqbase(job_type):
    return {
            "version": "1.0",
            "job_id": "",
            "job_type": job_type,
            "timestamp": "%s" % str(time.time()),
            "user_name": "super_dba",
            "paras": {}
            }

def send_request(url, json_obj, asjson=True):
    json_data = json.dumps(json_obj, indent=4)
    rep = requests.post(url, data=json_data)
    if asjson:
        return rep.json()
    else:
        return rep.text

# the return from request is like:
'''
{
'attachment': {'master_host': '192.168.0.110:57001'}, 
'error_code': '0', 'error_info': 'ok', 'job_id': '', 'job_type': '', 'status': 'donversion': '1.0'
}
'''
def get_meta_master(url):
    json_obj = get_reqbase("get_meta_master")
    repobj = send_request(url, json_obj)
    if repobj['error_code'] == '0':
        return repobj['attachment']['master_host']
    else:
        return None

# the return is like:
'''
{
'attachment': {
    'list_meta': [
        {'hostaddr': '192.168.0.110', 'master': 'true', 'port': '57001', 'status': 'online'}, 
        {'hostaddr': '192.168.0.111', 'master': 'false', 'port': '57001', 'status': 'online'}, 
        {'hostaddr': '192.168.0.100', 'master': 'false', 'port': '57001', 'status': 'online'}
        ] }, 
'error_code': '0', 'error_info': '', 'job_id': '', 'job_type': '', 'status': 'done', 'version': '1.0'
}
'''
def get_meta_summary(url):
    json_obj = get_reqbase("get_meta_summary")
    return send_request(url, json_obj)

# The general return is like:
'''
{ "attachment":{return object},"error_code":"0","error_info":"OK","job_id":"","job_type":"","status":"done","version":"1.0" }
'''
def get_status(url, job_id):
    json_obj = get_reqbase("get_status")
    json_obj['job_id'] = str(job_id)
    return send_request(url, json_obj)

# return attachment from response object.
def get_info_from_jobid(url, job_id):
    repobj = get_status(url, job_id)
    if repobj['error_code'] == '0':
        return repobj['attachment']
    else:
        return None

def wait_status_internal(url, job_id, ins, checkNot=False, retry=200):
    cnt=0
    status = None
    while True:
        if cnt > retry:
            print("exceed retry limit %d, quit." % retry)
            return status
        ret = get_status(url, job_id)
        if 'status' not in ret:
            raise ValueError("bad return:%s" % str(ret))
        status = ret['status']
        if status == 'not_started':
            time.sleep(5)
            cnt=cnt+1
            continue
        if checkNot and status not in ins:
            return status
        if status in ins and not checkNot:
            return status
        time.sleep(5)
        cnt=cnt+1

def wait_status_until(url, job_id, ins, retries=100):
    return wait_status_internal(url, job_id, ins, False, retries)

def wait_status_until_not(url, job_id, ins, retries=100):
    return wait_status_internal(url, job_id, ins, True, retries)

def get_async_jobid(repobj):
    if repobj['error_code'] == '0':
        return repobj['job_id']
    else:
        return None

# The return is like, final result should be 'done' for status object if succeeds:
'''
{ 'attachment': None, 'error_code': '0', 'error_info': '', 'job_id': '1', 'status': 'accept', 'version': '1.0' }

for get_status(job_id), the return is like:
{
    'attachment': {
        'cluster_id': '1', 'cluster_name': 'cluster_1751335792_000001', 'computer_id': '3', 'computer_pwd': 'abc', 'computer_state': 'done', 
        'computer_step': [{
            'cluster_id': '1', 'cluster_name': 'cluster_1751335792_000001', 'computer_hosts': '192.168.0.110_47001;', 
            'computer_id': '5', 'computer_pwd': 'abc', 'computer_state': 'done', 'computer_user': 'abc', 
            'error_code': 0, 'error_info': 'OK', 'nick_name': 'test_db', 'rollback_flag': '1'}], 
        'computer_user': 'abc', 'job_steps': 'shard,computer', 'shard_id': '2', 
        'shard_step': [{
            'cluster_id': '1', 'cluster_name': 'cluster_1751335792_000001', 'error_code': 0, 'error_info': 'OK', 
            'ha_mode': 'rbr', 'nick_name': 'test_db', 'rollback_flag': '1', 
            'shard_hosts': [{
                'shard_1': '192.168.0.110_57004;192.168.0.111_57004;192.168.0.100_57004;'}], 
            'shard_ids': '1,', 'storage_state': 'done'}], 
        'storage_state': 'done'}, 
    'error_code': '0', 'error_info': 'OK', 'job_id': '', 'job_type': '', 'status': 'done', 'version': '1.0'
}
'''
def create_cluster(url, shards, replicas, comps, storage_iplists, computer_iplists, 
                        user_name='super_dba', nick_name='test_db', max_storage_size=1024,
                       max_connections=2000, cpu_cores=8, cpu_limit_node='quota', innodb_size=1024,
                       rocksdb_block_cache_size_M=1024, fullsync_level=1, data_storage_MB=1024, log_storage_MB=1024,
                       dbcfg=0, other_paras_dict=None):
    para = {"nick_name": nick_name, "ha_mode": "rbr", "shards": str(shards),
            "storage_iplists": storage_iplists, "computer_iplists": computer_iplists,
                "nodes": str(replicas), "comps": str(comps), "max_storage_size": str(max_storage_size),
                "max_connections": str(max_connections), "cpu_cores": str(cpu_cores),
                "cpu_limit_node": str(cpu_limit_node),"innodb_size": str(innodb_size),
                "rocksdb_block_cache_size_M": str(rocksdb_block_cache_size_M), "data_storage_MB": str(data_storage_MB),
                "log_storage_MB": str(log_storage_MB), "dbcfg": str(dbcfg), "fullsync_level": str(fullsync_level)}
    if other_paras_dict:
        para.update(other_paras_dict)
    json_obj = get_reqbase("create_cluster")
    json_obj['paras'] = para
    return send_request(url, json_obj)

# The return is like following, and the status object(get_status(jobid)) is same to create_cluster
'''
{ "attachment":null,"error_code":"0","error_info":"","job_id":"6","status":"accept","version":"1.0" }
'''
def delete_cluster(url, cluster_id):
    json_obj = get_reqbase("delete_cluster")
    json_obj['paras'] = {
                "cluster_id": str(cluster_id)
                }
    return send_request(url, json_obj)

# async req, get_status(jobid) is like following:
'''
{
    'attachment': {
        'cluster_id': '10', 'cluster_name': 'cluster_1751348325_000010', 'ha_mode': 'rbr', 'rollback_flag': '0', 
        'shard_hosts': [{'shard_2': '192.168.0.111_57007;192.168.0.100_57007;192.168.0.110_57007;'}], 
        'shard_ids': '11,', 'storage_state': 'done'
        }, 
    'error_code': '0', 'error_info': 'OK', 'job_id': '', 'job_type': '', 'status': 'done', 'version': '1.0'}

'''
def add_shards(url, cluster_id, shards, replicas, storage_iplists):
    json_obj = get_reqbase("add_shards")
    json_obj['paras'] = {
                    "cluster_id": str(cluster_id),
                    "shards": str(shards),
                    "nodes": str(replicas),
                    "storage_iplists": storage_iplists
                }
    return send_request(url, json_obj)

# for successful operation the statobj['attachment'] is like following:
'''
{
    'cluster_id': '10', 'rollback_flag': '0', 'shard_id': '14', 
    'storage_hosts': '192.168.0.111_57007;192.168.0.100_57007;192.168.0.110_57007;', 
    'storage_id': '113', 'storage_state': 'done'
}
'''
def delete_shard(url, cluster_id, shard_id):
    json_obj = get_reqbase("delete_shard")
    json_obj['paras'] = {
                    "cluster_id": str(cluster_id),
                    "shard_id": str(shard_id)
                }
    return send_request(url, json_obj)

# for successful operation, the statobj['attachment'] is like following, notice comp_id should be query from database:
'''
{
    'cluster_id': '10', 'cluster_name': 'cluster_1751348325_000010', 
    'computer_hosts': '192.168.0.111_47001;192.168.0.100_47001;', 'computer_id': '133',
    'computer_pwd': 'abc', 'computer_state': 'done', 'computer_user': 'abc', 'rollback_flag': '0'
    }
'''
def add_comps(url, cluster_id, comps, comps_iplist):
    json_obj = get_reqbase("add_comps")
    json_obj['paras'] =  {
                    "cluster_id": str(cluster_id),
                    "comps":  str(comps),
                    "computer_iplists": comps_iplist
                }
    return send_request(url, json_obj)

# for successful operaton, the statobj['attachment'] is like following:
'''
{
    'cluster_id': '10', 'comp_id': '18', 'computer_hosts': '192.168.0.100_47001;', 'computer_id': '147', 
    'computer_state': 'done', 'install_proxysql': '0', 'proxysql_state': 'done', 'rollback_flag': '0'
}
'''
def delete_comp(url, cluster_id, comp_id):
    json_obj = get_reqbase("delete_comp")
    json_obj['paras'] = {
                    "cluster_id": str(cluster_id),
                    "comp_id": str(comp_id)
                }
    return send_request(url, json_obj)

def add_nodes(url, cluster_id, shard_id, nodes_num, storage_iplists):
    json_obj = get_reqbase("add_nodes")
    json_obj['paras'] = {
                    "cluster_id": str(cluster_id),
                    "shard_id": str(shard_id),
                    "nodes": str(nodes_num),
                    "storage_iplists": storage_iplists
                }
    return send_request(url, json_obj)

def delete_node(url, cluster_id, shard_id, host, port):
    json_obj = get_reqbase("delete_node")
    json_obj['paras'] = {
                    "cluster_id": str(cluster_id),
                    "shard_id": str(shard_id),
                    "hostaddr": str(host),
                    "port": str(port)
                }
    return send_request(url, json_obj)

def table_repartition(url, src_cluster_id, dst_cluster_id, repartition_tables):
    json_obj = get_reqbase("table_repartition")
    json_obj['paras'] = {
                    "src_cluster_id": str(src_cluster_id),
                    "dst_cluster_id": str(dst_cluster_id),
                    "repartition_tables": str(repartition_tables)
                }
    return send_request(url, json_obj)

def logical_backup(url, cluster_id, backup_type, backup_info):
    json_obj = get_reqbase("logical_backup")
    json_obj['paras'] = {
                    "cluster_id": "%s" % cluster_id,
                    "backup_type": "%s" % backup_type,
                    "backup": backup_info 
                    }
    return send_request(url, json_obj)

def cluster_restore(url, src_cluster_id, dst_cluster_id, restore_time):
    json_obj = get_reqbase("cluster_restore")
    json_obj['paras'] = {
                    "src_cluster_id":str(src_cluster_id),
                    "dst_cluster_id": str(dst_cluster_id),
                    "restore_time": str(restore_time)
                }
    return send_request(url, json_obj)

def logical_restore(url, src_cluster_id, dst_cluster_id, restore_type, restore_info):
    json_obj = get_reqbase("logical_restore")
    json_obj['paras'] = {
                    "src_cluster_id": str(src_cluster_id),
                    "dst_cluster_id": str(dst_cluster_id),
                    "restore_type": str(restore_type),
                    "restore":  restore_info
                }
    return send_request(url, json_obj)

# The request should be sent to destination clustermgr
def create_rcr(url, src_cluster_id, dst_cluster_id, 
        skip_sync_roles="jenkins,agent,kunlun", ignore_db="0",
        meta_db=None, slave_meta_db=None):
    json_obj = get_reqbase("create_rcr")
    json_obj['paras'] = {
                   "master_info": {
                        "meta_db": str(meta_db),
                        "cluster_id": str(src_cluster_id)
                    },
                   "need_backup": "0",
                   "delay_sync": "0",
                   "ignore_db": str(ignore_db),
                   "sync_host_delay": "1800",
                   "cluster_id": str(dst_cluster_id),
                   "slave_rcr_meta": str(slave_meta_db),
                   "skip_sync_roles": skip_sync_roles
                }
    return send_request(url, json_obj)

def modify_rcr(url,rcr_id, src_cluster_id, dst_cluster_id, meta_db, work_mode):
    json_obj = get_reqbase("modify_rcr")
    json_obj['paras'] = {
                   "master_info": {
                        "meta_db": str(meta_db),
                        "cluster_id": str(src_cluster_id)
                    },
                   "rcr_id": str(rcr_id),
                   "cluster_id": str(dst_cluster_id),
                   "work_mode": work_mode
                }
    return send_request(url, json_obj)

def stop_rcr(url,rcr_id, src_cluster_id, dst_cluster_id, meta_db):
    return modify_rcr(url,rcr_id, src_cluster_id, dst_cluster_id, meta_db, "stop_rcr")

def start_rcr(url,rcr_id, src_cluster_id, dst_cluster_id, meta_db):
    return modify_rcr(url,rcr_id, src_cluster_id, dst_cluster_id, meta_db, "start_rcr")

def manualsw_rcr(url, src_cluster_id, dst_cluster_id, meta_db, delay=30):
    json_obj = get_reqbase("manualsw_rcr")
    json_obj['paras'] = {
                   "master_info": {
                        "meta_db": str(meta_db),
                        "cluster_id": str(src_cluster_id)
                    },
                    "cluster_id": str(dst_cluster_id),
                    "allow_sw_delay": str(delay)
                }
    return send_request(url, json_obj)

def delete_rcr(url, src_cluster_id, dst_cluster_id, meta_db):
    json_obj = get_reqbase("delete_rcr")
    json_obj['paras'] = {
                   "master_info": {
                        "meta_db": str(meta_db),
                        "cluster_id": str(src_cluster_id)
                    },
                    "cluster_id": str(dst_cluster_id)
                }
    return send_request(url, json_obj)

def set_noswitch(url, cluster_id, shard_id, timeout_sec):
    json_obj = get_reqbase("set_noswitch")
    json_obj['paras'] = {
                    "cluster_id": str(cluster_id),
                    "shard_id": str(shard_id),
                    "timeout": str(timeout_sec),
                    "type": "1"
                }
    return send_request(url, json_obj)

def rebuild_node(url, cluster_id, shard_id, host, port, 
        need_backup=0, hdfs_host='hdfs', pv_limit=10, allow_pull_from_master=1,
        allow_replica_delay=15):
    json_obj = get_reqbase("rebuild_node")
    json_obj['paras'] = {
                    "shard_id": str(shard_id),
                    "cluster_id": str(cluster_id),
                    "rb_nodes": [
                        {
                            "hostaddr": str(host),
                            "port": str(port),
                            "need_backup":str(need_backup),
                            "hdfs_host": hdfs_host,
                            "pv_limit": str(pv_limit)
                        }
                    ],
                    "allow_pull_from_master": str(allow_pull_from_master),
                    "allow_replica_delay": str(allow_replica_delay)
                }
    return send_request(url, json_obj)

def manual_backup_cluster(url, cluster_id, nick_name):
    json_obj = get_reqbase("manual_backup_cluster")
    json_obj['paras'] = {
                    "cluster_id": str(cluster_id),
                    "nick_name": nick_name
                }
    return send_request(url, json_obj)

def expand_cluster(url, cluster_id, src_shard_id, dst_shard_id, table_list):
    json_obj = get_reqbase("expand_cluster")
    json_obj['paras'] = {
                "cluster_id": str(cluster_id),
                "src_shard_id": str(src_shard_id),
                "dst_shard_id": str(dst_shard_id),
                "table_list": table_list
              }
    return send_request(url, json_obj)

def control_instance(url, host, port, machine_type, control_type):
    json_obj = get_reqbase("control_instance")
    json_obj['paras'] = {
                "hostaddr": host,
                "port": str(port),
                "machine_type": machine_type,
                "control": control_type
                }
    return send_request(url, json_obj)

def update_cluster_coldback_time_period(url, cluster_id, time_period_str=None):
    json_obj = get_reqbase("update_cluster_coldback_time_period")
    json_obj['paras'] = {
                   "cluster_id": str(cluster_id),
                   "time_period_str": time_period_str
                     }
    return send_request(url, json_obj)

def update_instance_cgroup(url, ip, port, node_type='mysql', cpu_cores=8, cgroup_mode='quota'):
    json_obj = get_reqbase("update_instance_cgroup")
    json_obj['paras'] = {
                "ip": ip,
                "port": str(port),
                "type": node_type,
                "cpu_cores": str(cpu_cores),
                "cgroup_mode": str(cgroup_mode)
                }
    return send_request(url, json_obj)












