from fastapi import Request,Depends, APIRouter, UploadFile,HTTPException,File
from io import BytesIO
import typing as t
import pandas as pd
import json
import httpx
import deepdiff
import app.core.config as c


kinton_router = r = APIRouter()

def getfieldsfromexcel(df):
    appname = df.iloc[0,2]
    col=[]
    for row in range(5,len(df)):
        if pd.isna(df.iloc[row,1]):
            break
        if not df.iloc[row,3] in c.KINTONE_FIELD_TYPE:
            continue
        p=[] 
        for column in range(1,7):
            if(not pd.isna(df.iloc[row,column])):
                if(property[column-1]=="options"):
                    o=[]
                    for v in df.iloc[row,column].split(','):
                        o.append(f"\"{v.split('|')[0]}\":{{\"label\":\"{v.split('|')[0]}\",\"index\":\"{v.split('|')[1]}\"}}") 
                    p.append(f"\"{property[column-1]}\":{{{','.join(o)}}}")
                elif(property[column-1]=="required"):
                    p.append(f"\"{property[column-1]}\":{df.iloc[row,column]}")
                else:
                    p.append(f"\"{property[column-1]}\":\"{df.iloc[row,column]}\"")
        col.append(f"\"{df.iloc[row,2]}\":{{{','.join(p)}}}")
    fields = ",".join(col).replace("False","false").replace("True","true")
    return  json.loads(f"{{{fields}}}")  

def getsettingfromexcel(df):
    appname = df.iloc[0,2]
    des = df.iloc[2,2]
    return {"name":appname,"description":des}

def getsettingfromkintone(app:str):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
    params = {"app":app}
    url = f"{c.BASE_URL}{c.API_V1_STR}/app/settings.json"
    r = httpx.get(url,headers=headers,params=params)
    return r.json()

def analysesettings(excel,kintone):
    updatesettings={}
    updates =   excel.keys() & kintone.keys()
    for key in updates:
        if excel[key] != kintone[key]:
            updatesettings[key] = excel[key]
    return updatesettings

def createkintoneapp(name:str):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
    data = {"name":name}
    url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app.json"
    r = httpx.post(url,headers=headers,data=json.dumps(data))
    return r.json()

def updateappsettingstokintone(app:str,updates:dict):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
    url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/settings.json"
    data = {"app":app}
    data.update(updates)
    r = httpx.put(url,headers=headers,data=json.dumps(data))
    return r.json()

def addfieldstokintone(app:str,fields:dict,revision:str = None):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
    url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json"
    if revision != None:
        data = {"app":app,"revision":revision,"properties":fields}
    else:
        data = {"app":app,"properties":fields}
    r = httpx.post(url,headers=headers,data=json.dumps(data))
    return r.json()

def updatefieldstokintone(app:str,revision:str,fields:dict):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
    url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json"
    data = {"app":app,"properties":fields}
    r = httpx.put(url,headers=headers,data=json.dumps(data))
    return r.json()

def deletefieldsfromkintone(app:str,revision:str,fields:dict):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
    url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json"
    params = {"app":app,"revision":revision,"fields":fields}
    #r = httpx.delete(url,headers=headers,content=json.dumps(params))
    r = httpx.request(method="DELETE",url=url,headers=headers,content=json.dumps(params))
    return r.json()

def deoployappfromkintone(app:str,revision:str):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
    url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/deploy.json"
    data = {"apps":[{"app":app,"revision":revision}],"revert": False}
    r = httpx.post(url,headers=headers,data=json.dumps(data))
    return r.json
    
def getfieldsfromkintone(app):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
    params = {"app":app}
    url = f"{c.BASE_URL}{c.API_V1_STR}/app/form/fields.json"
    r = httpx.get(url,headers=headers,params=params)
    return r.json()

def analysefields(excel,kintone):
    updatefields={}
    addfields={}
    delfields=[]
    updates =   excel.keys() & kintone.keys()
    adds = excel.keys() - kintone.keys()
    dels = kintone.keys() - excel.keys()
    for key in updates:
        for p in property:
           if excel[key].get(p) != None and kintone[key][p] != excel[key][p]:
                updatefields[key] = excel[key]
                break
    for key in adds:
        addfields[key] = excel[key]
    for key in dels:
        if kintone[key]["type"] in c.KINTONE_FIELD_TYPE:
           delfields.append(key)

    return {"update":updatefields,"add":addfields,"del":delfields}

def getprocessfromkintone(app:str):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
    params = {"app":app}
    url = f"{c.BASE_URL}{c.API_V1_STR}/app/status.json"
    r = httpx.get(url,headers=headers,params=params)
    return r.json()

def getassigneefromkintone(name,users,orgs):
    if name in ["作成者"]:
        return {"type":"ONE","entities":[{
                "entity": {
                 "type": "FIELD_ENTITY",
                 "code": name
                },
                "includeSubs": False
                }]}
    for user in users:
        if user["name"] == name:
            return {"type":"ONE","entities":[{
                "entity": {
                 "type": "USER",
                 "code": user["code"]
                },
                "includeSubs": False
                }]}
    for org in orgs:
        if org["organization"]["name"] == name:
            return {"type":"ONE","entities":[{
                "entity": {
                 "type": "ORGANIZATION",
                 "code": org["organization"]["code"]
                },
                "includeSubs": False
                }]}
    return  {"type":"ONE","entities":[]}

def getprocessfromexcel(df,users,orgs):
    begin = df[df[df.columns[1]].isin(["◆プロセス"])].index.values[0]
    status=[]
    actions=[]
    result ="{{}}"
    for row in range(begin+2,len(df)):
        n = df.iloc[row,1]
        i = df.iloc[row,0]
        a = df.iloc[row,2]
        t =  df.iloc[row,4]
        u = df.iloc[row,3]
        if pd.isna(u):
            status.append(f"\"{n}\":{{\"name\":\"{n}\",\"index\":\"{i}\",\"assignee\":{{\"type\":\"ONE\",\"entities\":[]}}}}")
        else:
            status.append(f"\"{n}\":{{\"name\":\"{n}\",\"index\":\"{i}\",\"assignee\":{json.dumps(getassigneefromkintone(u,users,orgs))}}}")
        if not pd.isna(t):
            actions.append(f"{{\"name\":\"{a}\",\"from\":\"{n}\",\"to\":\"{t}\",\"filterCond\":\"\"}}")
    result =  f"{{\"states\":{{{','.join(status)}}}, \"actions\": [{','.join(actions)}]}}"
    return json.loads(result)

def analysprocess(excel,kintone):
    excel.update({"enable":kintone["enable"],"revision":kintone["revision"]})
    diff = deepdiff.DeepDiff(excel,kintone)
    # diffstates =   excel["states"].keys() ^ kintone["states"].keys()
    # diffactions =  set(excel["actions"]).difference(set(kintone["actions"]
    
    # for item in diff:
    #     if item[0] != "enable" and item[0] != "app"  and item[0] != "revision":
    #         return True
    return diff

def updateprocesstokintone(app:str,process:dict):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
    url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/status.json"
    data = {"app":app,"enable":True}
    data.update(process)
    r = httpx.put(url,headers=headers,data=json.dumps(data))
    return r.json()

def getkintoneusers():
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
    url = f"{c.BASE_URL}/v1/users.json"
    r = httpx.get(url,headers=headers)
    return r.json()

def getkintoneorgs():
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
    params = {"code":c.KINTONE_USER}
    url = f"{c.BASE_URL}/v1/user/organizations.json"
    r = httpx.get(url,headers=headers,params=params)
    return r.json()

@r.post("/test",)
async def test(file:UploadFile= File(...),app:str=None):
    if file.filename.endswith('.xlsx'):
        try:
            content = await file.read()
            df = pd.read_excel(BytesIO(content))
            users = getkintoneusers()
            orgs =  getkintoneorgs()
            # excel = getprocessfromexcel(df)
            # kintone = getprocessfromkintone(app)
            # process = analysprocess(excel,kintone)
            test = getprocessfromexcel(df,users["users"], orgs["organizationTitles"])
            # excel =  getfieldsfromexcel(df)
            # if(app != None):
            #     kintone = getfieldsfromkintone(app)
            #     fields = analysefields(excel,kintone["properties"])                             
        except Exception as e:
            raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}")
    else:
        raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
       
    return test 


@r.post("/upload",)
async def upload(files:t.List[UploadFile] = File(...)):
    dataframes = []
    for file in files:
        if file.filename.endswith('.xlsx'):
            try:
                content = await file.read()
                df = pd.read_excel(BytesIO(content))
                print(df)
                dataframes.append(df)
            except Exception as e:
                raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}")
        else:
            raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
       
    return {"files": [file.filename for file in files]}  

@r.get("/allapps",)
async def allapps():
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
    url = f"{c.BASE_URL}{c.API_V1_STR}/apps.json"
    r = httpx.get(url,headers=headers)
    return r.json()

@r.get("/app")
async def app(app:str):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
    url = f"{c.BASE_URL}{c.API_V1_STR}/app.json"
    params ={"id":app}
    r = httpx.get(url,headers=headers,params=params)
    return r.json()


@r.get("/appfields")
async def appfields(app:str):
    return getfieldsfromkintone(app)

@r.get("/appprocess")
async def appprocess(app:str):
    return getprocessfromkintone(app)

@r.get("/alljscs")
async def alljscs(app:str):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
    url = f"{c.BASE_URL}{c.API_V1_STR}/app/customize.json"
    params = {"app":app}
    r = httpx.get(url,headers=headers,params=params)
    return r.json()

@r.post("/createapp",)
async def createapp(name:str):
    headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
    data = {"name":name}
    url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app.json"
    r = httpx.post(url,headers=headers,data=json.dumps(data))
    result = r.json()
    if result.get("app") != None:
        url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/deploy.json"
        data = {"apps":[result],"revert": False}
        r = httpx.post(url,headers=headers,data=json.dumps(data))
    return r.json

property=["label","code","type","required","defaultValue","options"]

@r.post("/createappfromexcel",)
async def createappfromexcel(files:t.List[UploadFile] = File(...)):
    for file in files:
        if file.filename.endswith('.xlsx'):
            try:
                content = await file.read()
                df = pd.read_excel(BytesIO(content))
               #アプリ名
                appname = df.iloc[0,2]
                desc = df.iloc[2,2] 
                result = {"app":0,"revision":0,"msg":""}
                fields = getfieldsfromexcel(df)
                users = getkintoneusers()
                orgs =  getkintoneorgs()
                processes = getprocessfromexcel(df,users["users"], orgs["organizationTitles"])
                app = createkintoneapp(appname)
                if app.get("app") != None:
                    result["app"] = app["app"]
                    app = updateappsettingstokintone(result["app"],{"description":desc})
                if app.get("revision") != None:
                    result["revision"] = app["revision"]
                    app = addfieldstokintone(result["app"],fields)
                if len(processes)> 0:
                    app = updateprocesstokintone(result["app"],processes)
                if app.get("revision") != None:
                    result["revision"] = app["revision"]
                    deoployappfromkintone(result["app"],result["revision"])
            except Exception as e:
                raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}")
        else:
            raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
       
    return result


@r.post("/updateappfromexcel",)
async def updateappfromexcel(app:str,files:t.List[UploadFile] = File(...)):
    for file in files:
        if file.filename.endswith('.xlsx'):
            try:
                content = await file.read()
                df = pd.read_excel(BytesIO(content))
                excel = getsettingfromexcel(df)
                kintone= getsettingfromkintone(app)
                settings = analysesettings(excel,kintone)
                excel = getfieldsfromexcel(df)
                kintone = getfieldsfromkintone(app)
                users = getkintoneusers()
                orgs =  getkintoneorgs()
                exp = getprocessfromexcel(df,users["users"], orgs["organizationTitles"])
                #exp = getprocessfromexcel(df)
                kinp = getprocessfromkintone(app)
                process = analysprocess(exp,kinp)
                revision = kintone["revision"]
                fields = analysefields(excel,kintone["properties"])
                result = {"app":app,"revision":revision,"msg":"No Update"}
                deploy = False
                if len(fields["update"]) > 0:
                    result = updatefieldstokintone(app,revision,fields["update"])
                    revision = result["revision"]
                    deploy = True
                if len(fields["add"]) > 0:
                    result = addfieldstokintone(app,fields["add"],revision)
                    revision = result["revision"]
                    deploy = True
                if len(fields["del"]) > 0:
                    result = deletefieldsfromkintone(app,revision,fields["del"])
                    revision = result["revision"]
                    deploy = True
                if len(settings) > 0:
                    result = updateappsettingstokintone(app,settings)
                    revision = result["revision"]
                    deploy = True
                if len(process)>0:
                    result = updateprocesstokintone(app,exp)
                    revision = result["revision"]
                    deploy = True
                if deploy:
                    result = deoployappfromkintone(app,revision)
            except Exception as e:
                raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}")
        else:
            raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
       
    return result

@r.post("/updateprocessfromexcel",)
async def updateprocessfromexcel(app:str):
   
    try:
        excel = getprocessfromexcel()
        kintone = getprocessfromkintone(app)
        revision = kintone["revision"]
        #fields = analysefields(excel,kintone["properties"])
        result = {"app":app,"revision":revision,"msg":"No Update"}
        deploy = False
        # if len(fields["update"]) > 0:
        #     result = updatefieldstokintone(app,revision,fields["update"])
        #     revision = result["revision"]
        #     deploy = True
        # if len(fields["add"]) > 0:
        #     result = addfieldstokintone(app,fields["add"],revision)
        #     revision = result["revision"]
        #     deploy = True
        # if len(fields["del"]) > 0:
        #     result = deletefieldsfromkintone(app,revision,fields["del"])
        #     revision = result["revision"]
        #     deploy = True
        # if len(settings) > 0:
        #     result = updateappsettingstokintone(app,settings)
        #     revision = result["revision"]
        #     deploy = True
        result = updateprocesstokintone(app,excel)
        revision = result["revision"]
        deploy = True
        if deploy:
            result = deoployappfromkintone(app,revision)
    except Exception as e:
        raise HTTPException(status_code=400, detail=f"Error occurred : {str(e)}")
       
    return result


