from datetime import datetime, timedelta
from calendar import monthrange


from netforce.model import Model, fields, get_model
from netforce.utils import get_data_path
from netforce.access import get_active_company, get_active_user, set_active_user
from netforce.database import get_connection

DAYS={
    0: 'mon',
    1: 'tue',
    2: 'wed',
    3: 'thu',
    4: 'fri',
    5: 'sat',
    6: 'sun',
}

class ClinicSetting(Model):
    _name="clinic.setting"
    _string="Setting"
    _field_name="var_k"
    
    def _get_name(self,ids,context={}):
        res={}
        for obj in self.browse(ids):
            res[obj.id]='xxx'
        return res

    _fields={
        'name': fields.Char("Name", function="_get_name"),
        "var_k": fields.Float("K"),
        'signature': fields.File("Signature"),
        'levels': fields.One2Many("clinic.setting.level","setting_id","Levels"),
        'products': fields.One2Many("clinic.setting.product","setting_id","Products"),
        'account_products': fields.One2Many("clinic.setting.account.product","setting_id","Account Products"),
        'account_patients': fields.One2Many("clinic.setting.account.patient","setting_id","Account Patients"),
        'shop_products': fields.One2Many("clinic.setting.shop.product","setting_id","Shop Products"),
        'invoice_policies': fields.One2Many("clinic.setting.policy","setting_id","Invoice Policies"),
        'cost_per_case': fields.Float("Cost Per Case"),
        'company_id': fields.Many2One("company", 'Company'),
        'period_id': fields.Many2One("clinic.period","Period"),
        'waiting_approval': fields.Boolean("Waiting Approval"), # HD Case
        'real_time': fields.Boolean("Real Time"), # HD Case
        'patient_type_id': fields.Many2One("clinic.patient.type","Default Type"), # Import payment
        'imp_patient_type_id': fields.Many2One("clinic.patient.type","Import UC Type"), # Import payment
        'find_dlz': fields.Boolean("Find Dialyzer After Confirm Visit"), # Visit
        'auto_gen_visit': fields.Boolean("Auto Generate Visit Before Next Month"), # Visit
        'stock_journal_id': fields.Many2One("stock.journal","Default Journal"),
        'auto_gen': fields.Boolean("Auto Gen"), # HD Case
        'schd_from': fields.Date("From"),
        'schd_to': fields.Date("To"),
        'department_id': fields.Many2One("clinic.department","Department"),
        'branch_id': fields.Many2One("clinic.branch","Branch"),
        'shop_categs': fields.Many2Many("product.categ","Categs"),
        'shop_type_id': fields.Many2One("clinic.patient.type","Patient Type"),
        'skip_type_id': fields.Many2One("clinic.patient.type","Skip Type"), # Matching HD Case
        "cash_account_id": fields.Many2One("account.account","Cash Account",multi_company=True),
        "income_account_id": fields.Many2One("account.account","Income Account",multi_company=True),
        "import_account_id": fields.Many2One("account.account","Import Account",multi_company=True),
        'helper_categ_id': fields.Many2One("clinic.staff.categ","Helper Category"),
        'base_salary_day': fields.Float("Base Salary Day"),
        'next_date': fields.DateTime("Next Gen"),
    }

    _defaults={
        "company_id": lambda *a: get_active_company(),
    }

    def onchange_line(self,context={}):
        data=context['data']
        path=context['path']
        line=get_data_path(data,path,parent=True)
        var_a=line['var_a'] or ''
        var_b=line['var_b'] or ''
        op=line['op'] or ''
        line['formular']='%sX%s%s'%(var_a,op,var_b)
        return data

    def onchange_product(self,context={}):
        data=context['data']
        path=context['path']
        line=get_data_path(data,path,parent=True)
        product_id=line['product_id']
        if product_id:
            prod=get_model("product").browse(product_id)
            uom=prod.uom_id
            if not uom:
                uom=get_model("uom").browse(1)
                if not uom:
                    raise Exception("Not found uom 'Unit'")
            line['uom_id']=uom.id
            line['description']=prod.name
            price=prod.sale_price or 0.0
            line['price']=price
            categ=prod.categ_id
            if categ:
                line['product_categ_id']=categ.id
            qty=1
            amt=qty*price
            line['amount']=amt
        return data

    def onchange_ptype(self,context={}):
        data=context['data']
        path=context['path']
        line=get_data_path(data,path,parent=True)
        return data

    def onchange_setting_line(self,context={}):
        data=context['data']
        path=context['path']
        line=get_data_path(data,path,parent=True)
        qty=line['qty'] or 0
        price=line['price'] or 0
        amt=qty*price
        line['amount']=amt
        return data

    def schd_confirm(self,ids,context={}):
        obj=self.browse(ids)[0]
        if not obj.schd_from:
            raise Exception("No date from")
        if not obj.schd_to:
            raise Exception("No date to")
        dom=[]
        dom.append(['date', '>=', obj.schd_from])
        dom.append(['date', '<=', obj.schd_to])
        for schd in get_model('clinic.schedule').search_browse(dom):
            schd.confirm()
        return True

    def remove_rotation(self,ids,context={}):
        staffs={}
        for rt in get_model("clinic.staff.rotation").search_browse([]):
            staff=rt.staff_id 
            if staff.name not in staffs:
                staffs[staff.name]=[rt.id]
            else:
                staffs[staff.name].append(rt.id)
        for st_name, vals in staffs.items():
            for rt_id in vals:
                rt=get_model("clinic.staff.rotation").browse(rt_id)
                if not rt.level_id:
                    rt.delete() 
        print("Done!")
        return

    def update_cycle_item_level(self,ids,context={}):
        for citem in get_model("clinic.cycle.item").search_browse([]):
            for line in citem.lines:
                nurse=line.nurse_id
                if nurse.level_id:
                    line.write({
                        'level_id': nurse.level_id.id,
                    })

    def run_script(self,ids,context={}):
        user_id=get_active_user()
        if user_id !=1:
            print("Only admin!!")
            return
        categ_ids=get_model('product.categ').search([['parent_id.code','=','MDC']])
        for prod in get_model("product").search_browse([['categ_id','in',categ_ids]]):
            prod.write({
                'report_visible': True,
            })
        #for dt in get_model("district").search_browse([]):
            #name=(dt.name or "")[0:1]
            #dt.write({
                #'sort_name': name,
            #})
        #for sdt in get_model("subdistrict").search_browse([]):
            #name=(sdt.name or "")[0:1]
            #sdt.write({
                #'sort_name': name,
            #})
        print("Done!")

    def merge_staff(self,ids,context={}):
        user_id=get_active_user()
        if user_id !=1:
            print("Only admin!!")
            return
        sts={}
        db=get_connection()
        for st in get_model("clinic.staff").search_browse([]):
            name='%s %s'%(st.first_name or '', st.last_name or '')
            name=name.replace(" ","")
            name=''.join([n for n in name if n.isalpha()])
            if not sts.get(name):
                sts[name]=[]
            sts[name].append({
                'id': st.id,
                'name': name,
                'branch_id': st.department_id.id,
                'type': st.type,
                'date': st.date,
            })

        for st, vals in sts.items():
            vals=sorted(vals,key=lambda x: x['date'])
            count=len(vals)
            if count > 1:
                print("z"*50)
                id_lines=[]
                no=0
                for val in vals:
                    no+=1
                    staff_id=val['id']
                    staff_type=val['type']
                    if staff_type=='nurse':
                        res=get_model("clinic.cycle.item.line").search_browse([['nurse_id','=',staff_id]])
                        if len(res)<=0:
                            print('nurse zero delete ', st)
                            get_model('clinic.staff').delete([staff_id])
                        else:
                            print('merge nurse... ', st, staff_id, val['date'], val['branch_id'], len(res))
                            print('no ', no, len(vals), len(res))
                            if no==len(vals):
                                print("--> ", staff_id, id_lines)
                                for id_line in id_lines:
                                    for rec in get_model("clinic.cycle.item.line").search_browse([['nurse_id','=',id_line]]):
                                        rec.write({
                                            'nurse_id': staff_id,
                                        })
                                    dom=[
                                        ['type','=','nurse'],
                                        ['staff_id','=',id_line],
                                    ]
                                    for lcost in get_model("clinic.labor.cost.line").search_browse(dom):
                                        lcost.write({
                                            'staff_id': staff_id,
                                        })
                            id_lines.append(staff_id)
                    elif staff_type=='doctor':
                        res=get_model("clinic.hd.case.staff").search_browse([['staff_id','=',staff_id]])
                        if len(res)<=0:
                            print('doctor zero delete ', st)
                            for le in get_model("clinic.labor.cost.entry.line").search_browse([['staff_id','=',staff_id]]):
                                le.delete()
                            get_model('clinic.staff').delete([staff_id])
                        else:
                            print('merge doctor... ', st, staff_id, val['date'], val['branch_id'], len(res))
                            if no==len(vals):
                                print("--> ", staff_id, id_lines)
                                db=get_connection()
                                for id_line in id_lines:
                                    for rec in get_model("clinic.hd.case.staff").search_browse([['staff_id','=',id_line]]):
                                        rec.write({
                                            'staff_id': staff_id,
                                        })
                                        hdcase=rec.hd_case_id
                                        vs=hdcase.visit_id
                                        #vs.write({
                                            #'doctor_id': staff_id,
                                        #})
                                        db.execute("update clinic_visit set doctor_id=%s where id=%s",staff_id,vs.id)
                                        pt=hdcase.patient_id
                                        #pt.write({
                                            #'doctor_id': staff_id,
                                        #})
                                        db.execute("update clinic_patient set doctor_id=%s where id=%s",staff_id,pt.id)
                                        citem=hdcase.cycle_item_id
                                        dom=[
                                            ['type','=','doctor'],
                                            ['staff_id','=',id_line],
                                            ['labor_cost_id.cycle_item_id','=',citem.id],
                                        ]
                                        for lcost in get_model("clinic.labor.cost.line").search_browse(dom):
                                            lcost.write({
                                                'staff_id': staff_id,
                                            })
                            id_lines.append(staff_id)
                print("z"*50)
        print("Done!")

    def del_duplicate_staff(self,ids,context={}):
        user_id=get_active_user()
        if user_id !=1:
            print("Only admin!!")
            return
        pts={}
        for pt in get_model("clinic.patient").search_browse([]):
            name='%s %s'%(pt.first_name or "", pt.last_name or "")
            if not pts.get(name):
                pts[name]=[]
            pts[name].append({
                'id': pt.id,
                'name': name,
                'date': pt.reg_date,
                'branch_id': pt.department_id.id,
            })
        sts={}
        print('='*50, 'patients duplicate')
        db=get_connection()
        for pt, vals in pts.items():
            vals=sorted(vals,key=lambda x: x['date'])
            count=len(vals)
            no=0
            if count > 1:
                id_lines=[]
                for val in vals:
                    no+=1
                    pt_id=val['id']
                    print(no, val['id'], val['name'], val['date'])
                    if no==len(vals):
                        for del_pt_id in id_lines:
                            visit_ids=[]
                            hdcase_ids=[]
                            print('del_pt_id ', del_pt_id)
                            for hdcase in get_model('clinic.hd.case').search_browse([['patient_id','=',del_pt_id]]):
                                visit_ids.append(hdcase.visit_id.id)
                                hdcase_ids.append(hdcase.id)
                            print('hdcase_ids ', hdcase_ids, 'visit_ids ', visit_ids)
                            if hdcase_ids:
                                print('>>>>>>>> pt_id ', pt_id)
                                db.execute('update clinic_hd_case set patient_id=%s where id in %s', pt_id,tuple(hdcase_ids))
                                db.execute('update clinic_visit set patient_id=%s where id in %s', pt_id,tuple(visit_ids))
                                db.execute('update clinic_dialyzer set patient_id=%s where patient_id = %s', pt_id,del_pt_id)
                                #for hdcase in get_model("clinic.hd.case").browse(hdcase_ids):
                                    #hdcase.write({
                                        #'patient_id': pt_id,
                                    #})
                                #for vs in get_model("clinic.visit").browse(visit_ids):
                                    #vs.write({
                                        #'patient_id': pt_id,
                                    #})
                                #for dlz in get_model("clinic.dialyzer").search_browse([['patient_id','=',del_pt_id]]):
                                    #dlz.write({
                                        #'patient_id': pt_id,
                                    #})
                                for ap in get_model("clinic.setting.account.patient").search_browse([['patient_id','=',del_pt_id]]):
                                    ap.write({
                                        'patient_id': pt_id,
                                    })
                                for hdce in get_model("clinic.hd.case.expense").search_browse([['patient_id','=',del_pt_id]]):
                                    hdce.write({
                                        'patient_id': pt_id,
                                    })
                                #get_model('clinic.patient').delete([del_pt_id])
                                for pt in get_model('clinic.patient').browse([del_pt_id]):
                                    pt.write({
                                        'first_name': '__%s'% pt.first_name or "",
                                        'active': False,
                                    })
                            else:
                                print('patient zero delete ', val)
                                for vs in get_model("clinic.visit").search_browse([['patient_id','=',del_pt_id]]):
                                    vs.write({
                                        'patient_id': pt_id,
                                    })
                                for dlz in get_model("clinic.dialyzer").search_browse([['patient_id','=',del_pt_id]]):
                                    dlz.write({
                                        'patient_id': pt_id,
                                    })
                                for ap in get_model("clinic.setting.account.patient").search_browse([['patient_id','=',del_pt_id]]):
                                    ap.write({
                                        'patient_id': pt_id,
                                    })
                                for hdce in get_model("clinic.hd.case.expense").search_browse([['patient_id','=',del_pt_id]]):
                                    hdce.write({
                                        'patient_id': pt_id,
                                    })
                                #get_model('clinic.patient').delete([del_pt_id])
                                for pt in get_model('clinic.patient').browse([del_pt_id]):
                                    pt.write({
                                        'first_name': '__%s'% pt.first_name or "",
                                        'active': False,
                                    })
                        print('---> ', pt_id, id_lines, val['date'])
                    else:
                        id_lines.append(pt_id)

        print('='*50, 'staffs duplicate')
        for st in get_model("clinic.staff").search_browse([]):
            name='%s %s'%(st.first_name or '', st.last_name or '')
            name=name.replace(" ","")
            if not sts.get(name):
                sts[name]=[]
            sts[name].append({
                'id': st.id,
                'name': name,
                'branch_id': st.department_id.id,
                'type': st.type,
                'date': st.date,
            })

        for st, vals in sts.items():
            vals=sorted(vals,key=lambda x: x['date'])
            count=len(vals)
            if count > 1:
                print("z"*50)
                id_lines=[]
                no=0
                for val in vals:
                    no+=1
                    staff_id=val['id']
                    staff_type=val['type']
                    if staff_type=='nurse':
                        res=get_model("clinic.cycle.item.line").search_browse([['nurse_id','=',staff_id]])
                        if len(res)<=0:
                            print('nurse zero delete ', st)
                            get_model('clinic.staff').delete([staff_id])
                        else:
                            print('merge nurse... ', st, staff_id, val['date'], val['branch_id'], len(res))
                            print('no ', no, len(vals), len(res))
                            if no==len(vals):
                                print("--> ", staff_id, id_lines)
                                for id_line in id_lines:
                                    for rec in get_model("clinic.cycle.item.line").search_browse([['nurse_id','=',id_line]]):
                                        rec.write({
                                            'nurse_id': staff_id,
                                        })
                                    dom=[
                                        ['type','=','nurse'],
                                        ['staff_id','=',id_line],
                                    ]
                                    for lcost in get_model("clinic.labor.cost.line").search_browse(dom):
                                        lcost.write({
                                            'staff_id': staff_id,
                                        })
                            id_lines.append(staff_id)
                    elif staff_type=='doctor':
                        res=get_model("clinic.hd.case.staff").search_browse([['staff_id','=',staff_id]])
                        if len(res)<=0:
                            print('doctor zero delete ', st)
                            get_model('clinic.staff').delete([staff_id])
                        else:
                            print('merge doctor... ', st, staff_id, val['date'], val['branch_id'], len(res))
                            if no==len(vals):
                                print("--> ", staff_id, id_lines)
                                db=get_connection()
                                for id_line in id_lines:
                                    for rec in get_model("clinic.hd.case.staff").search_browse([['staff_id','=',id_line]]):
                                        rec.write({
                                            'staff_id': staff_id,
                                        })
                                        hdcase=rec.hd_case_id
                                        vs=hdcase.visit_id
                                        #vs.write({
                                            #'doctor_id': staff_id,
                                        #})
                                        db.execute("update clinic_visit set doctor_id=%s where id=%s",staff_id,vs.id)
                                        pt=hdcase.patient_id
                                        #pt.write({
                                            #'doctor_id': staff_id,
                                        #})
                                        db.execute("update clinic_patient set doctor_id=%s where id=%s",staff_id,pt.id)
                                        citem=hdcase.cycle_item_id
                                        dom=[
                                            ['type','=','doctor'],
                                            ['staff_id','=',id_line],
                                            ['labor_cost_id.cycle_item_id','=',citem.id],
                                        ]
                                        for lcost in get_model("clinic.labor.cost.line").search_browse(dom):
                                            lcost.write({
                                                'staff_id': staff_id,
                                            })
                            id_lines.append(staff_id)
                print("z"*50)
        ###TODO remove douplicate patient
        ###TODO remove douplicate staff
        ###TODO remove douplicate visit
        print("Done!")

    def multi_department(self,ids,context={}):
        user_id=get_active_user()
        if user_id !=1:
            print("Only admin!!")
            return
        ### udpate working location for staff
        staffs={}
        for hdcase in get_model('clinic.hd.case').search_browse([]):
            dpt=hdcase.department_id
            doctor=hdcase.doctor_id
            citem=hdcase.cycle_item_id
            if not citem:
                continue
            for cline in citem.lines:
                nurse=cline.nurse_id
                if nurse.id not in staffs.keys():
                    staffs[nurse.id]=set()
                staffs[nurse.id].update({dpt.id})
            if doctor.id not in staffs.keys():
                staffs[doctor.id]=set()
            staffs[doctor.id].update({dpt.id})
        for st_id, dpt_ids in staffs.items():
            if not st_id:
                continue
            st=get_model('clinic.staff').browse(st_id)
            olds=[dpt.id for dpt in st.departments]
            for dpt_id in dpt_ids:
                if dpt_id not in olds:
                    st.write({
                        'departments': [('add',[dpt_id])],
                    })
        #### update patient location
        for pt in get_model("clinic.patient").search_browse([]):
            pt.write({
                'note': ' ',
            })
        #### update department
        #### by visit
        dpt_ids=get_model("clinic.department").search([])
        fmt='%Y-%m-%d'
        for pt in get_model("clinic.patient").search_browse([]):
            cycles={}
            print('len ', len(pt.visits))
            for hd in pt.hd_cases:
                if hd.department_id:
                    date=hd.date
                    wd=datetime.strptime(date,fmt).weekday()
                    key='%s-%s-%s'%(hd.department_id.id, hd.cycle_id.id, wd)
                    if not key in cycles.keys():
                        cycles[key]={
                            'department_id': hd.department_id.id,
                            'cycle_id':  hd.cycle_id.id,
                            'day': wd,
                        }
            print('cycles ', cycles)
            if not pt.cycles and cycles:
                clines=[]
                for key, cycle_vals in cycles.items():
                    clines.append(('create',cycle_vals)),
                pt.write({
                    'cycles': clines,
                })
                print('update cycle for ', pt.name)
            elif pt.cycles:
                continue #XXX
                clines=[]
                x1=set(cycles.keys())
                x2=set()
                for pcycle in pt.cycles:
                    pcycle_id=pcycle.cycle_id.id
                    pdpt_id=pcycle.department_id.id
                    wd=pcycle.day
                    key2='%s-%s-%s'%(pdpt_id,pcycle_id, wd)
                    x2.update({key2})
                for cvals in (x1.difference(x2)):
                    dpt_id, cycle_id, day=cvals.split("-")
                    clines.append(('create', {
                        'department_id': int(dpt_id),
                        'cycle_id': int(cycle_id),
                        'day': day,
                    }))
                if clines:
                    print("---- > update the rest ", clines)
                    pt.write({
                        'cycles': clines,
                    })
            else:
                pass
        for st in get_model("clinic.staff").search_browse([]):
            if not st.departments:
                st.write({
                    'departments': [['set',dpt_ids]],
                })
                print('set all department for ', st.name)

        print('Done!')
        return

    def update_patient_file(self,path='/tmp/',file_lines=[]):
        import csv
        for file_line in file_lines:
            if path.endswith("/"):
                path=path[0:len(path)-1] # remove /
            fpath="/".join([path,file_line])
            f=open(fpath,"r")
            rd=csv.reader(f)
            row1=next(rd)
            headers=[]
            for header in row1:
                header='_'.join([x.lower() for x in header.split()])
                headers.append(header)
            lines=[]
            for row in rd:
                vals=dict(zip(headers,row)) 
                lines.append(vals)

            def get_dicts(model_name,dom=[]):
                res={}
                if not model_name:
                    return res
                for sr in get_model(model_name).search_read(dom,['name']):
                    res[sr['name']]=sr['id']
                return res
            vasculars=get_dicts('clinic.vascular.access')
            cycles=get_dicts('clinic.cycle')
            titles=get_dicts('clinic.name.title')
            default_title=None
            for tname, tid in titles.items():
                if tname=='No Title':
                    default_title=tid 
                    break
            types=get_dicts('clinic.patient.type')
            dpts=get_dicts('clinic.department')
            doctors=get_dicts(model_name='clinic.staff',dom=['type','=','doctor'])
            days={
                'Monday': 'mon',
                'Tuesday': 'tue',
                'Wednesday': 'wed',
                'Thursday': 'thu',
                'Friday': 'fri',
                'Saturday': 'sat',
                'Sunday': 'sun',
            }
            datas={}
            olds=set({})
            dbid2=0
            dpt_id=None
            for line in lines:
                dbid=line['database_id']
                if dbid not in olds:
                    dbid=line['database_id']
                    dbid2=dbid
                else:
                    dbid=dbid2
                olds.update({dbid})
                fname=line['first_name']
                lname=line['last_name']
                dname=line['doctor']
                cycle=line['cycles/cycle']
                cycle=cycles.get(cycle,None)
                day=line['cycles/day']
                day=days.get(day)
                dpt=line['department']
                dpt=dpts.get(dpt,None)
                if not dpt:
                    dpt=dpt_id
                else:
                    dpt_id=dpt
                bday=line['birthday'] or None
                title=line['title']
                title=titles.get(title,default_title) or None
                idcard=line['id_card']
                trt=line['trt']
                type=line['type']
                type=types.get(type,None)
                valc=line['vascular_ac.']
                valc=vasculars.get(valc)
                hn=line['hn_number']
                if not datas.get(dbid):
                    datas[dbid]={
                        'card_no': (idcard or "").replace(" ",""),
                        'number': hn,
                        'type_id': type,
                        'first_name': fname,
                        'last_name': lname,
                        'birthday': bday,
                        'title_id': title,
                        'trt_no': trt,
                        'doctor_id': doctors.get(dname),
                        'vascular_acc': valc,
                        'department_id': dpt,
                    }
            print(" update patient data")
            for patient_id, vals in datas.items():
                if not patient_id:
                    continue
                try:
                    m,d,y=(vals['birthday'] or "").split("/")
                    vals['birthday']='%s-%s-%s'%(y,m.zfill(2),d.zfill(2))
                except Exception as e:
                    print("ERROR: ",e)
                if not vals['card_no']:
                    vals['card_no']='/'
                else:
                    vals['card_no']=''.join([x for x in vals['card_no'] if x.isdigit()])
                    # recheck
                    if not vals['card_no']:
                        vals['card_no']='/'
                pvals=vals.copy()
                print(pvals)
                get_model("clinic.patient").browse(int(patient_id)).write(pvals)
            print("Done!")

    def update_pcycle(self,path='/tmp/',file_lines=[]):
        import csv
        for file_line in file_lines:
            if path.endswith("/"):
                path=path[0:len(path)-1] # remove /
            fpath="/".join([path,file_line])
            print('fpath ', fpath)
            f=open(fpath,"r")
            rd=csv.reader(f)
            row1=next(rd)
            headers=[]
            for header in row1:
                header='_'.join([x.lower() for x in header.split()])
                headers.append(header)
            lines=[]
            for row in rd:
                vals=dict(zip(headers,row)) 
                lines.append(vals)

            def get_dicts(model_name,dom=[]):
                res={}
                if not model_name:
                    return res
                for sr in get_model(model_name).search_read(dom,['name']):
                    res[sr['name']]=sr['id']
                return res

            vasculars=get_dicts('clinic.vascular.access')
            cycles=get_dicts('clinic.cycle')
            titles=get_dicts('clinic.name.title')
            default_title=None
            for tname, tid in titles.items():
                if tname=='No Title':
                    default_title=tid 
                    break
            types=get_dicts('clinic.patient.type')
            dpts=get_dicts('clinic.department')
            doctors=get_dicts(model_name='clinic.staff',dom=['type','=','doctor'])
            days={
                'Monday': 'mon',
                'Tuesday': 'tue',
                'Wednesday': 'wed',
                'Thursday': 'thu',
                'Friday': 'fri',
                'Saturday': 'sat',
                'Sunday': 'sun',
            }
            datas={}
            olds=set({})
            dbid2=0
            dpt_id=None
            for line in lines:
                dbid=line['database_id']
                if dbid not in olds:
                    dbid=line['database_id']
                    dbid2=dbid
                else:
                    dbid=dbid2
                olds.update({dbid})
                fname=line['first_name']
                lname=line['last_name']
                dname=line['doctor']
                cycle=line['cycles/cycle']
                cycle=cycles.get(cycle,None)
                day=line['cycles/day']
                day=days.get(day)
                dpt=line['department']
                dpt=dpts.get(dpt,None)
                if not dpt:
                    dpt=dpt_id
                else:
                    dpt_id=dpt
                bday=line['birthday'] or None
                title=line['title']
                title=titles.get(title,default_title) or None
                idcard=line['id_card']
                trt=line['trt']
                type=line['type']
                type=types.get(type,None)
                valc=line['vascular_ac.']
                valc=vasculars.get(valc)
                hn=line['hn_number']
                if not datas.get(dbid):
                    datas[dbid]={
                        'card_no': (idcard or "").replace(" ",""),
                        'number': hn,
                        'type_id': type,
                        'first_name': fname,
                        'last_name': lname,
                        'birthday': bday,
                        'title_id': title,
                        'trt_no': trt,
                        'doctor_id': doctors.get(dname),
                        'vascular_acc': valc,
                        'cycles': [],
                    }
                if dbid and cycle and day:
                    datas[dbid]['cycles'].append({'department_id': dpt, 'cycle_id': cycle, 'day': day})

            def check_pcycle(patient_id,cycle_id,day,department_id):
                dom=[
                    ['patient_id','=',patient_id],
                    ['cycle_id','=',cycle_id],
                    ['day','=',day],
                    ['department_id','=',department_id],
                ]
                ids=get_model("clinic.patient.cycle").search(dom)
                print("found pcycle:  ", ids)
                return ids
            def create_pcycle(all_vals):
                new_ids=[]
                for vals in all_vals:
                    try:
                        id=get_model("clinic.patient.cycle").create(vals)
                    except Exception as e:
                        print("ERROR : ", e)
                    new_ids.append(id)
                print("pcycle create ", new_ids)

            print(" update patient data")
            all_vals=[]
            for patient_id, vals in datas.items():
                if not patient_id:
                    continue
                try:
                    m,d,y=(vals['birthday'] or "").split("/")
                    vals['birthday']='%s-%s-%s'%(y,m.zfill(2),d.zfill(2))
                except Exception as e:
                    print("ERROR : ", e)
                if not vals['card_no']:
                    vals['card_no']='/'
                else:
                    #get only number
                    vals['card_no']=''.join([x for x in vals['card_no'] if x.isdigit()])
                pvals=vals.copy()
                del pvals['cycles']
                patient=get_model("clinic.patient").browse(int(patient_id))
                print(patient_id, ' ----> ', pvals)
                patient.write(pvals)
                for cvals in vals['cycles']:
                    cycle_id=cvals['cycle_id']
                    day=cvals['day']
                    department_id=cvals['department_id']
                    if not check_pcycle(patient_id,cycle_id,day,department_id):
                        cvals.update({'patient_id': patient_id})
                        all_vals.append(cvals)
            create_pcycle(all_vals)
            print("Done!")

    def update_staff_department(self,ids,context={}):
        user_id=get_active_user()
        if user_id !=1:
            print("Only admin!!")
            return
        b={}
        for dpt in get_model("clinic.department").search_browse([]):
            branch=dpt.branch_id
            if not branch.id in b:
                b[branch.id]=[]
            b[branch.id].append(dpt.id)

        for staff in get_model("clinic.staff").search_browse([]):
            if not staff.departments:
                dpt=staff.department_id
                branch=staff.branch_id
                dpt_ids=[]
                if dpt:
                    dpt_ids.append(dpt.id)
                elif branch:
                    dpt_ids=b.get(branch.id)
                staff.write({
                    'departments': [('set',dpt_ids)],
                })
                print(staff.name)
        print("Done!")
        return

    def update_staff_level(self,ids,context={}):
        user_id=get_active_user()
        if user_id !=1:
            print("Only admin!!")
            return
        # run below before above!
        import csv
        f=open("/tmp/update_rotation.csv","r")
        rd=csv.reader(f)
        headers=next(rd)
        headers=[h.lower().replace(" ","") for h in headers]
        lines=[]
        for row in rd:
            vals=dict(zip(headers,row))
            lines.append(vals)
        levels={}
        for level in get_model("clinic.staff.level").search_read([]):
            levels[level['name']]=level['id']
        categories={}
        for categ in get_model("clinic.staff.categ").search_read([]):
            categories[categ['name']]=categ['id']
        for line in lines:
            db_id=int(line['databaseid'])
            level=line['level']
            level_id=levels.get(level,None)
            catetory=line['category']
            categ_id=categories.get(catetory,None)
            rt=get_model('clinic.staff.rotation').browse(db_id)
            rt.write({
               'level_id': level_id,
               'categ_id': categ_id,
            })

        #force update level, category store
        for staff in get_model("clinic.staff").search_browse([]):
            staff.write({
                'note': ' ', 
            })
        for citem in get_model("clinic.cycle.item").search_browse([]):
            for line in citem.lines:
                nurse=line.nurse_id
                categ_id=nurse.categ_id
                level_id=nurse.level_id
                line.write({
                    'categ_id': categ_id.id,
                    'level_id': level_id.id,
                })
        print("Done!")
        return

    def remove_douplicate_visit(self,ids,context={}):
        user_id=get_active_user()
        set_active_user(1)
        for pt in get_model("clinic.patient").search_browse([]):
            dates=[]
            print("="*50)
            for visit in pt.visits:
                if visit.state=='confirmed':
                    continue
                if visit.visit_date in dates:
                    print(pt.name, ' delete ', visit.visit_date)
                    visit.to_draft()
                    visit.delete()
                dates.append(visit.visit_date) 
            print("="*50)
        set_active_user(user_id)
        print("Done!")
        return

    def export_staff_rotation_csv(self,ids,context={}):
        user_id=get_active_user()
        if user_id !=1:
            print("Only admin!!")
            return
        lines=[]
        for rt in get_model("clinic.staff.rotation").search_browse([]):
            staff=rt.staff_id
            if staff.type!='nurse':
                continue
            level_name=''
            if staff.level_id:
                level_name=staff.level_id.name
            lines.append({
                'id': rt.id,
                'name': staff.name,
                'level': level_name,
                'categ': staff.categ_id.name or "",
            })
        st="Database ID,Staff,Level,Category\n" 
        for line in sorted(lines,key=lambda x: x['name']):
            st+="%s,%s,%s,%s\n"%(line['id'],line['name'],line['level'],line['categ'])
        f=open("/tmp/rotation.csv","w")
        f.write(st)
        f.close()
        print("Done!")
        return

    def update_departments(self,ids,context={}):
        user_id=get_active_user()
        if user_id !=1:
            print("Only admin!!")
            return
        for st in get_model("clinic.staff").search_browse([]):
            dpt_ids=set()
            if st.departmet_id:
                dpt_ids.update({st.departmet_id.id})
            if st.type=='doctor':
                for hdcase in st.hd_case_staffs:
                    dpt_ids.update({hdcase.department_id.id})
            elif st.type=='nurse':
                for citem in st.cycle_item_nurses:
                    dpt_ids.update({citem.department_id.id})
            else:
                continue
            #FIXME 
            db=get_connection()
            for dpt_id in dpt_ids:
                if not dpt_id:
                    continue
                sql="insert into m2m_clinic_department_clinic_staff values(%s,%s)"%(st.id, dpt_id)
                # clinic_staff_id
                # clinic_department_id
                db.execute(sql)
            #st.write({
                #'departments': {'add': [1]},
            #})
            #break
            print('update dpt %s'%st.name)

        print("Done!")

    def update_staff_contact(self,ids,context={}):
        user_id=get_active_user()
        if user_id !=1:
            print("Only admin!!")
            return
        pids=[]
        for st in get_model("clinic.staff").search_browse([]):
            code=st.number
            partner=st.partner_id
            if partner:
                partner.write({
                    'code': code,
                    'is_staff': True,
                })
                pids.append(partner.id)
        for pt in get_model("clinic.patient").search_browse([]):
            code=pt.hn_no or ""
            partner=pt.partner_id
            if partner:
                partner.write({
                    'code': code,
                    'is_patient': True,
                })
                pids.append(partner.id)
        
        for ptype in get_model('clinic.patient.type').search_browse([]):
            partner=ptype.contact_id
            if partner:
                pids.append(partner.id)
        
        #pids='(%s)'%(','.join([str(x) for x in pids]))
        db=get_connection()
        if pids:
            res=db.query("select id, name from partner where id not in %s", tuple(pids))
            pids=[r['id'] for r in res]
            for pt in get_model("partner").browse(pids):
                pt.write({
                    'active': False,
                })
        #for partner in get_model("partner").search_browse([]):
            #pass

        print("Done!")

    def update_name(self,ids,context={}):
        user_id=get_active_user()
        if user_id !=1:
            print("Only admin!!")
            return
        titles=dict([(t.name, t.id) for t in get_model("clinic.name.title").search_browse([])])
        title_id=None
        gtitle_id=title_id
        for name, tid in titles.items():
            if name=='No Title':
                gtitle_id=tid
        for model_name in ('clinic.staff', 'clinic.patient'):
            for st in get_model(model_name).search_browse([]):
                name=st.name
                vals={}
                if 'นายแพทย์' in name:
                    name=name.replace("นายแพทย์","")
                    tname='นายแพทย์'
                    title_id=titles.get(tname)
                    vals.update({
                        'title_id': title_id,
                        'gender': 'male',
                    })
                elif 'นพ.' in name:
                    name=name.replace("นพ.","")
                    tname='นพ.'
                    title_id=titles.get(tname)
                    vals.update({
                        'title_id': title_id,
                        'gender': 'male',
                    })
                elif 'นาย' in name:
                    name=name.replace("นาย","")
                    tname='นาย'
                    title_id=titles.get(tname)
                    vals.update({
                        'title_id': title_id,
                        'gender': 'male',
                    })
                elif 'พันตำรวจเอก' in name:
                    name=name.replace("พันตำรวจเอก","")
                    tname='พันตำรวจเอก'
                    title_id=titles.get(tname)
                    vals.update({
                        'title_id': title_id,
                        'gender': 'male',
                    })
                elif 'นางสาว' in name:
                    name=name.replace("นางสาว","")
                    tname='นางสาว'
                    title_id=titles.get(tname)
                    vals.update({
                        'title_id': title_id,
                        'gender': 'female',
                    })
                elif 'นาง' in name:
                    name=name.replace("นาง","")
                    tname='นาง'
                    title_id=titles.get(tname)
                    vals.update({
                        'title_id': title_id,
                        'gender': 'female',
                    })
                elif 'น.ส.' in name:
                    name=name.replace("น.ส.","")
                    tname='น.ส.'
                    title_id=titles.get(tname)
                    vals.update({
                        'title_id': title_id,
                        'gender': 'female',
                    })
                elif 'พญ..' in name:
                    name=name.replace("พญ..","")
                    tname='พญ..'
                    title_id=titles.get(tname)
                    vals.update({
                        'title_id': title_id,
                        'gender': 'female',
                    })
                elif 'แพทย์หญิง' in name:
                    name=name.replace("แพทย์หญิง","")
                    tname='แพทย์หญิง'
                    title_id=titles.get(tname)
                    vals.update({
                        'title_id': title_id,
                        'gender': 'female',
                    })
                elif 'ร้อยเอกหญิง' in name:
                    name=name.replace("ร้อยเอกหญิง","")
                    tname='ร้อยเอกหญิง'
                    title_id=titles.get(tname)
                    vals.update({
                        'title_id': title_id,
                        'gender': 'female',
                    })
                elif 'พันตรีหญิง' in name:
                    name=name.replace("พันตรีหญิง","")
                    tname='พันตรีหญิง'
                    title_id=titles.get(tname)
                    vals.update({
                        'title_id': title_id,
                        'gender': 'female',
                    })
                elif 'พันตำรวจโทหญิง' in name:
                    name=name.replace("พันตำรวจโทหญิง","")
                    tname='พันตำรวจโทหญิง'
                    title_id=titles.get(tname)
                    vals.update({
                        'title_id': title_id,
                        'gender': 'female',
                    })
                else:
                    vals.update({
                        'first_name': name, #XXX
                        'title_id': gtitle_id,
                        #'gender': 'male',
                    })
                names=name.split()
                names=[n for n in names if n] # skip space
                if len(names)==2:
                    vals.update({
                        'first_name':names[0],
                        'last_name': names[1],
                    })
                else:
                    vals.update({
                        'first_name':name,
                    })
                    print(name)
                st.write(vals)
                if not st.gender:
                    st.write({
                        'gender': 'male',
                    })
        print("Done!")

    def reset_last_import(self,ids,context={}):
        res=get_model("clinic.report.payment.matching").search_read([],['date'],order="date desc")
        if res:
            db=get_connection()
            res1=res[0]
            date1='%s 00:00:00'%res1['date']
            date2='%s 23:59:59'%res1['date']
            exp_ids=[x['id'] for x in db.query("select id from clinic_hd_case_expense where write_time>=%s and write_time<=%s",date1,date2)]
            for exp in get_model("clinic.hd.case.expense").browse(exp_ids):
                exp.write({
                    'state': 'waiting_matching',
                    'ok': False,
                })
                for inv in exp.invoices:
                    payment=inv.payment_id
                    if payment:
                        if payment.state !='draft':
                            payment.to_draft()
                            print("to draft payment ", payment.id)
        print("Done")
    
    def get_product_account(self,ids,prod_id=None,patient_type_id=None,pay_type='credit',context={}):
        res={}
        print("find ", prod_id, patient_type_id, pay_type)
        dom=[['type','=',pay_type]]
        for ac_prod in get_model("clinic.setting.account.product").search_browse(dom):
            prod=ac_prod.product_id
            ptype=ac_prod.patient_type_id
            if patient_type_id==ptype.id and prod_id==prod.id:
                print("found !")
                res.update({
                    'ar_credit_id': ac_prod.ar_credit_id.id,
                    'ar_debit_id': ac_prod.ar_debit_id.id,
                })
                break 
        print("res ", res)
        return res

    def get_patient_hn(self,ids,context={}):
        obj=self.browse(ids)[0] 
        res={
            'hns':{},
            'names': {},
        }
        for line in obj.account_patients:
            pt=line.patient_id
            name=line.partner_id.name or ""
            vals={
                'hn': pt.hn,
                'pid': pt.id,
                'card_no': pt.card_no,
                'name': "%s%s"%(pt.first_name or "", pt.last_name or ""),
            }
            name=name.replace(" ","")
            if name not in res['names'].keys():
                res['names'][name]=vals
            hn=line.hn
            if hn not in res['hns'].keys():
                res['hns'][hn]=vals
        return res
    
    def generate_visit(self,ids,context={}):
        obj=self.browse(ids)[0]
        if obj.auto_gen_visit:
            datenow=datetime.now().strftime("%Y-%m-%d")
            year,month,day=datenow.split("-")
            weekday, total_day=monthrange(int(year), int(month))
            date_from="%s-%s-%s"%(year,month,"01")
            date_to="%s-%s-%s"%(year,month,("%s"%total_day).zfill(2))
            mobj=get_model('clinic.make.apt')
            vals={
                'date_from': date_from,
                'date_to': date_to,
            }
            print('duration generate ', vals)
            mid=mobj.create(vals)
            m=mobj.browse(mid)
            m.load(context=context)
            m.gen(context=context)

    def auto_generate_visit(self,ids,context={}):
        obj=self.browse(ids)[0]
        print("auto generate visit running...")
        datenow=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        print('now : ', datenow, 'next gen :',obj.next_date)
        print('ans: ', datenow>=obj.next_date)
        if datenow>=obj.next_date:
            obj.generate_visit()
            # update next job
            date=datetime.now()
            y,m,d=date.strftime("%Y-%m-%d").split("-")
            m=int(m)
            if m>=12:
                m=1
                y=int(y)+1
            else:
                m+=1
            m=str(m).zfill(2)
            next_date='%s-%s-%s 00:00:00'%(y,m,'01')
            obj.write({
                'next_date': next_date,
            })
            print("Done!")
        print("Next Gen is ", obj.next_date)
    
    def manual_generate_visit(self,ids,context={}):
        dom=[]
        dom.append(['name','=','Generate Visit'])
        sec=10 # waiting in 10 sec
        date=datetime.now()+timedelta(0,sec) # days, seconds
        next_date=date.strftime("%Y-%m-%d %H:%M:%S")
        obj=self.browse(ids)[0]
        obj.write(
            { 'next_date': next_date,
        })
        print('next runing in 10 seconds  ', date)

ClinicSetting.register()