import json,re,time,datetime
from pathlib import Path
import requests

WS=Path('/Users/ahmad/.openclaw/workspace')
TOKEN=re.search(r'(pk_[A-Za-z0-9_]+)',(WS/'clickup_credentials.md').read_text()).group(1)
H={'Authorization':TOKEN,'Content-Type':'application/json'}
BASE='https://api.clickup.com/api/v2'

backup_dirs=sorted((WS/'clickup_restructure_backup').glob('*'))
latest=backup_dirs[-1]
inv_tasks=json.loads((latest/'tasks_by_list.json').read_text())
inv_lists=json.loads((latest/'lists.json').read_text())


def get(url,params=None):
    r=requests.get(url,headers=H,params=params,timeout=40)
    r.raise_for_status(); return r.json()

def post(url,data):
    r=requests.post(url,headers=H,json=data,timeout=40)
    r.raise_for_status(); return r.json()

def norm(s): return re.sub(r'\s+',' ',(s or '').strip().lower())

def dkey(t):
    for k in ['due_date','start_date','date_created']:
        v=t.get(k)
        if v:
            return datetime.datetime.utcfromtimestamp(int(v)/1000).date().isoformat()
    return 'none'

def choose(t):
    n=(t.get('name') or '').lower(); s=((t.get('status') or {}).get('status') or '').lower(); due=t.get('due_date')
    if any(x in n for x in ['meeting','call','follow up','follow-up','1:1']): return 'Meetings & Follow-ups'
    if any(x in n for x in ['recurring','weekly','daily','monthly','routine']): return 'Recurring Ops'
    if 'block' in s or 'wait' in s or any(x in n for x in ['waiting','blocked','dependency']): return 'Waiting / Blocked'
    if s in ['complete','done','closed']: return 'Archive'
    if due:
        days=(int(due)/1000-time.time())/86400
        if days<=1.5:return 'Today'
        if days<=7.5:return 'This Week'
    return 'Pipeline'

team=get(f'{BASE}/team')['teams'][0]
spaces=get(f"{BASE}/team/{team['id']}/space",params={'archived':'false'})['spaces']
ops=next(s for s in spaces if s['name']=='Ops')
lists=get(f"{BASE}/space/{ops['id']}/list",params={'archived':'false'})['lists']
want=['Today','This Week','Pipeline','Waiting / Blocked','Recurring Ops','Meetings & Follow-ups','Archive']
list_map={l['name']:l for l in lists if l['name'] in want}

idx=set()
for n,l in list_map.items():
    ts=get(f"{BASE}/list/{l['id']}/task",params={'include_closed':'true','subtasks':'true'}).get('tasks',[])
    for t in ts: idx.add((l['id'],norm(t.get('name')),dkey(t)))

legacy=[l for l in inv_lists if l['id'] not in {x['id'] for x in list_map.values()}]
migrated=[]; dup=[]; unresolved=[]; processed=0
for li in legacy:
    for t in inv_tasks.get(li['id'],[]):
        processed+=1
        tgt=choose(t)
        tl=list_map[tgt]
        k=(tl['id'],norm(t.get('name')),dkey(t))
        if k in idx:
            dup.append(t['id']); continue
        tags=[]
        for tg in t.get('tags') or []:
            if isinstance(tg,dict) and tg.get('name'): tags.append(tg['name'])
            elif isinstance(tg,str): tags.append(tg)
        src=t.get('url') or f"https://app.clickup.com/t/{t['id']}"
        payload={'name':t.get('name'),'description':f"[Migrated from legacy task {t['id']}]({src})\n\n{t.get('description') or ''}",'tags':sorted(set(tags+['migrated-from-legacy'])),'notify_all':False}
        if t.get('due_date'): payload['due_date']=int(t['due_date'])
        if t.get('start_date'): payload['start_date']=int(t['start_date'])
        if t.get('assignees'): payload['assignees']=[a['id'] for a in t['assignees'] if a.get('id')]
        try:
            c=post(f"{BASE}/list/{tl['id']}/task",payload)
            migrated.append({'src':t['id'],'name':t.get('name'),'target_list':tgt,'url':c.get('url'),'id':c.get('id')})
            idx.add(k)
        except Exception as e:
            unresolved.append({'task':t.get('id'),'err':str(e)})

out={'migrated':migrated,'skipped_duplicates':len(dup),'unresolved':unresolved,'processed':processed,'backup':str(latest)}
(WS/'clickup_restructure_backup'/latest.name/'migration_results.json').write_text(json.dumps(out,indent=2))
print(json.dumps({'migrated':len(migrated),'dups':len(dup),'unresolved':len(unresolved),'backup':str(latest)},indent=2))
