#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
form_cmd.py — команды и КНОПКИ формы в Form.elem.json (дополняет form_inspect/form_edit).

Подтверждённый формат (см. reference/object_metadata.md §«Команды и кнопки»):
  Команда формы (секция elem['commands'], список {name,id,raw}):
    raw = ["9", ["<id>","409b9a53-7f7e-4178-86c1-33176c7c7a7a"], "\"Имя\"",
           ["1","1",["\"ru\"","\"Заголовок\""]],   # raw[3] синоним = текст кнопки
           ["1","1",["\"ru\"","\"Подсказка\""]],   # raw[4]
           ..., "\"ИмяПроцедуры\"", ...]           # raw[8] = обработчик (&НаКлиенте Процедура Имя(Команда))
    uuid 409b9a53-... — маркер ФОРМЕННОЙ команды.
  Кнопка (head "31", внутри raw таблицы или панели):
    [0]"31" [6]"\"ИмяЭлемента\"" [7]<title>  [9]<привязка [cmd-id, cmd-uuid]>
    title=["1","0"] → брать заголовок из синонима команды; ["1","1",["ru","Текст"]] → свой текст.
    Встроенные команды (сортировка) имеют uuid != 409b9a53 — их можно ПЕРЕВЯЗАТЬ на форменную команду.

Команды:
  list      <elem.json>
  set-title <elem.json> --cmd <имя|id> --title "Текст"
  add-cmd   <elem.json> --name Имя --title "Текст"            # action = Имя (нужна одноимённая &НаКлиенте процедура)
  rebind    <elem.json> --table T --btn <подстрока-имени|uuid-привязки> --to-cmd <id> [--use-cmd-title]
"""
import sys, json, copy, argparse
CMD_UUID='409b9a53-7f7e-4178-86c1-33176c7c7a7a'

def load(p): return json.load(open(p,encoding='utf-8'))
def save(p,d): json.dump(d,open(p,'w',encoding='utf-8'),ensure_ascii=False,indent=2)

def find_buttons(raw):
    out=[]
    def w(o):
        if isinstance(o,list):
            if o and o[0]=='31' and len(o)>10: out.append(o)
            for v in o: w(v)
    w(raw); return out

def table_raw(e, table):
    for k,v in e['data'].items():
        if k.split('/')[-1]==table and isinstance(v.get('raw'),list) and v['raw'][0]=='55':
            return v['raw']
    return None

def cmd_list(args):
    e=load(args.elem)
    print("=== COMMANDS (секция commands) ===")
    for c in e.get('commands') or []:
        r=c['raw']
        title=r[3][2][1].strip('"') if isinstance(r[3],list) and len(r[3])>2 else '?'
        action=r[8].strip('"') if len(r)>8 and isinstance(r[8],str) else '?'
        print(f"  id={c['id']:>2} name={c['name']:<32} title='{title}' action={action}")
    print("=== BUTTONS в таблицах ('31') ===")
    for k,v in e['data'].items():
        if isinstance(v.get('raw'),list) and v['raw'][0]=='55':
            for b in find_buttons(v['raw']):
                # b[6] обычно строка-имя, но у форм, собранных платформой, бывает
                # списком (напр. ["1","0"]) — не падаем.
                nm=b[6].strip('"') if isinstance(b[6],str) else str(b[6])
                bind=b[9] if len(b)>9 else None
                t=b[7] if len(b)>7 else None
                try:
                    tt = ('cmd-syn' if t==['1','0'] else (t[2][1].strip('"') if isinstance(t,list) and len(t)>2 else '?'))
                except (IndexError,TypeError,AttributeError):
                    tt='?'
                print(f"  [{k.split('/')[-1]}] {nm:<46} bind={bind} title={tt}")

def get_cmd(e, ref):
    for c in e['commands']:
        if c['id']==str(ref) or c['name']==ref: return c
    return None

def set_title(raw, title):
    raw[3]=['1','1',['"ru"','"%s"'%title]]
    raw[4]=['1','1',['"ru"','"%s"'%title]]

def cmd_set_title(args):
    e=load(args.elem); c=get_cmd(e,args.cmd)
    if not c: sys.exit("команда не найдена: "+args.cmd)
    set_title(c['raw'], args.title); save(args.elem,e)
    print(f"set-title OK: команда {c['name']} -> '{args.title}'")

def cmd_add(args):
    e=load(args.elem); cmds=e['commands']
    ids=[int(c['id']) for c in cmds if c['id'].isdigit()]
    nid=str(max(ids)+1) if ids else '2'
    base=copy.deepcopy(cmds[0]); r=base['raw']
    base['name']=args.name; base['id']=nid
    r[1]=[nid, CMD_UUID]; r[2]='"%s"'%args.name
    set_title(r, args.title); r[8]='"%s"'%args.name
    # r[7] = ['4', <флаг>, [<idx>, <uuid-картинки>], ...] — картинка команды.
    # cmds[0] (обычно "Поставить/Снять галочки") часто несёт свою иконку;
    # без сброса кнопка рендерится ТОЛЬКО иконкой без подписи (баг DEVACC-755:
    # пользователь просил текстовые кнопки, получил безликие иконки).
    # Текстовая кнопка = "нет картинки": флаг '0', индекс без uuid.
    r[7]=['4','0',['0'],'""','-1','-1','1','0','""']
    cmds.append(base); save(args.elem,e)
    print(f"add-cmd OK: id={nid} name={args.name} title='{args.title}' action={args.name} (текстовая кнопка, без картинки)")
    print("  → добавь в модуль формы:  &НаКлиенте Процедура %s(Команда) ... КонецПроцедуры"%args.name)

def cmd_rebind(args):
    e=load(args.elem); raw=table_raw(e,args.table)
    if raw is None: sys.exit("таблица '%s' (тип 55) не найдена"%args.table)
    hits=0
    for b in find_buttons(raw):
        nm=b[6].strip('"'); bind=b[9] if len(b)>9 else [None,None]
        if args.btn in nm or (len(bind)>1 and args.btn==bind[1]):
            b[9]=[str(args.to_cmd), CMD_UUID]
            if args.use_cmd_title: b[7]=['1','0']
            hits+=1
            print(f"  rebind '{nm}' -> command id={args.to_cmd}")
    if not hits: sys.exit("кнопка не найдена по '%s'"%args.btn)
    save(args.elem,e); print(f"rebind OK ({hits})")

def main():
    ap=argparse.ArgumentParser(); sub=ap.add_subparsers(dest='cmd',required=True)
    p=sub.add_parser('list'); p.add_argument('elem'); p.set_defaults(fn=cmd_list)
    p=sub.add_parser('set-title'); p.add_argument('elem'); p.add_argument('--cmd',required=True); p.add_argument('--title',required=True); p.set_defaults(fn=cmd_set_title)
    p=sub.add_parser('add-cmd'); p.add_argument('elem'); p.add_argument('--name',required=True); p.add_argument('--title',required=True); p.set_defaults(fn=cmd_add)
    p=sub.add_parser('rebind'); p.add_argument('elem'); p.add_argument('--table',required=True); p.add_argument('--btn',required=True); p.add_argument('--to-cmd',required=True,dest='to_cmd'); p.add_argument('--use-cmd-title',action='store_true'); p.set_defaults(fn=cmd_rebind)
    a=ap.parse_args(); a.fn(a)

if __name__=='__main__': main()
