"""架空の請求下書きフォーム。mode: normal / corrupt(保存時に+1円) / lost(初回の応答だけ切断)。"""
import html, json, sys, threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

mode, port, out = sys.argv[1], int(sys.argv[2]), sys.argv[3]
records, log, lock = [], [], threading.Lock()
state = {"posts": 0}

def dump():
    json.dump({"mode": mode, "records": records, "log": log}, open(out, "w"), ensure_ascii=False)

FIELDS = [("customer_code", "顧客コード"), ("supplier", "仕入先名"), ("invoice_no", "請求番号"),
          ("invoice_date", "請求日"), ("total_jpy", "税込金額（円）")]

class H(BaseHTTPRequestHandler):
    def log_message(self, *_): pass
    def send(self, body, status=200):
        b = body.encode()
        self.send_response(status); self.send_header("Content-Type", "text/html; charset=utf-8")
        self.send_header("Content-Length", str(len(b))); self.end_headers(); self.wfile.write(b)
    def do_GET(self):
        with lock: log.append(["GET", self.path]); dump()
        if self.path == "/":
            inputs = "".join(f'<p><label>{l}<br><input name="{k}"></label></p>' for k, l in FIELDS)
            self.send("<h1>請求書の下書き登録</h1>" + inputs + '<button id="save">下書き保存</button><p id="status"></p>'
              "<script>document.querySelector('#save').onclick=async()=>{"
              "const d=Object.fromEntries([...document.querySelectorAll('input')].map(e=>[e.name,e.value]));"
              "try{const r=await fetch('/save',{method:'POST',body:JSON.stringify(d)});"
              "const j=await r.json();document.querySelector('#status').innerHTML="
              "'下書きを保存しました（登録ID: '+j.id+'）　<a href=\"/records\">一覧へ</a>';}"
              "catch(e){document.querySelector('#status').textContent='通信エラーが発生しました。もう一度お試しください。';}};</script>")
        elif self.path == "/records":
            rows = "".join(f'<tr><td>{('<a href="/record/'+r["id"]+'">'+r["id"]+'</a>') if mode != "zero" else r["id"]}</td><td>{html.escape(r["supplier"])}</td>'
                           f'<td>{html.escape(r["invoice_no"])}</td><td>{html.escape(r["total_jpy"])}</td></tr>' for r in records)
            self.send("<h1>下書き一覧</h1><table border=1><tr><th>登録ID</th><th>仕入先</th><th>請求番号</th><th>税込金額</th></tr>" + rows + "</table>")
        elif self.path.startswith("/record/"):
            if mode == "zero": return self.send("not found", 404)
            rid = self.path.split("/")[-1]
            r = next((x for x in records if x["id"] == rid), None)
            if not r: return self.send("not found", 404)
            self.send(f"<h1>下書き {rid}</h1>" + "".join(f"<p>{l}: <span>{html.escape(r[k])}</span></p>" for k, l in FIELDS))
        else:
            self.send("not found", 404)
    def do_POST(self):
        data = json.loads(self.rfile.read(int(self.headers["Content-Length"])))
        with lock:
            state["posts"] += 1
            saved = dict(data)
            if mode == "zero":
                saved["customer_code"] = data["customer_code"].lstrip("0")
            if mode == "corrupt":
                saved["total_jpy"] = str(int(data["total_jpy"]) + 1)
            rid = f"DRAFT-{len(records)+1:04d}"
            records.append({"id": rid, **saved})
            log.append(["POST", "/save", data]); dump()
            first = state["posts"] == 1
        if mode == "lost" and first:
            self.connection.shutdown(2); self.connection.close(); return
        self.send(json.dumps({"id": rid}))

ThreadingHTTPServer(("127.0.0.1", port), H).serve_forever()
