import json
import stat
import subprocess
import sys
import tempfile
import textwrap
import unittest
from pathlib import Path


SCRIPT = Path(__file__).resolve().parent / "openclaw_notes_crud.py"


def write_fake_cli(path: Path) -> None:
    body = """#!/usr/bin/env python3
import json
import sys

args = sys.argv[1:]

def out(obj):
    print(json.dumps(obj, ensure_ascii=False))

if args[:2] == ["docs", "+create"]:
    out({"ok": True, "data": {"doc_id": "dox_new", "doc_url": "https://feishu.example/docx/dox_new"}})
elif args[:2] == ["docs", "+fetch"]:
    out({"ok": True, "data": {"doc_id": "dox_read", "doc_url": "https://feishu.example/docx/dox_read", "markdown": "# read"}})
elif args[:2] == ["docs", "+update"]:
    out({"ok": True, "data": {"doc_id": "dox_update", "doc_url": "https://feishu.example/docx/dox_update", "args": args}})
elif args[:2] == ["docs", "+search"]:
    out({"ok": True, "data": {"items": [{"title": "note-1", "obj_token": "dox_1"}], "has_more": False}})
elif args[:2] == ["docs", "+media-insert"]:
    out({"ok": True, "data": {"document_id": "dox_media", "file_token": "file_x", "args": args}})
elif args[:2] == ["docs", "+media-download"]:
    out({"ok": True, "data": {"saved_path": "/tmp/downloaded.png", "content_type": "image/png", "args": args}})
elif args[:2] == ["drive", "+add-comment"]:
    out({"ok": True, "data": {"comment_id": "cmt_1", "args": args}})
elif args[:2] == ["api", "DELETE"]:
    out({"code": 0, "msg": "success", "data": {"deleted": True}})
else:
    sys.stderr.write("unexpected args: " + " ".join(args) + "\\n")
    sys.exit(2)
"""
    path.write_text(textwrap.dedent(body), encoding="utf-8")
    path.chmod(path.stat().st_mode | stat.S_IEXEC)


class OpenClawNotesCrudTest(unittest.TestCase):
    def run_cmd(self, args: list[str]) -> dict:
        with tempfile.TemporaryDirectory() as tmpdir:
            fake_cli = Path(tmpdir) / "fake_cli.py"
            write_fake_cli(fake_cli)
            cmd = [
                sys.executable,
                str(SCRIPT),
                "--lark-cli-bin",
                str(fake_cli),
            ] + args
            proc = subprocess.run(cmd, capture_output=True, text=True)
            self.assertEqual(proc.returncode, 0, proc.stderr)
            return json.loads(proc.stdout)

    def test_create(self):
        out = self.run_cmd(
            ["--op", "create", "--title", "t", "--markdown", "# hello"]
        )
        self.assertTrue(out["ok"])
        self.assertEqual(out["op"], "create")
        self.assertEqual(out["data"]["doc_id"], "dox_new")

    def test_read_update_search(self):
        read_out = self.run_cmd(["--op", "read", "--doc", "dox_read"])
        self.assertTrue(read_out["ok"])
        self.assertEqual(read_out["data"]["doc_id"], "dox_read")

        update_out = self.run_cmd(
            [
                "--op",
                "update",
                "--doc",
                "dox_update",
                "--mode",
                "append",
                "--markdown",
                "new content",
            ]
        )
        self.assertTrue(update_out["ok"])
        self.assertEqual(update_out["data"]["doc_id"], "dox_update")

        search_out = self.run_cmd(["--op", "search", "--query", "note"])
        self.assertTrue(search_out["ok"])
        self.assertEqual(search_out["data"]["items"][0]["obj_token"], "dox_1")

    def test_media_comment_and_section_update(self):
        media_insert_out = self.run_cmd(
            [
                "--op",
                "media-insert",
                "--doc",
                "dox_doc",
                "--file",
                "/tmp/test.png",
                "--media-type",
                "image",
                "--caption",
                "demo",
            ]
        )
        self.assertTrue(media_insert_out["ok"])
        self.assertEqual(media_insert_out["data"]["file_token"], "file_x")

        media_download_out = self.run_cmd(
            [
                "--op",
                "media-download",
                "--token",
                "file_x",
                "--output",
                "/tmp/downloaded",
                "--overwrite",
            ]
        )
        self.assertTrue(media_download_out["ok"])
        self.assertEqual(media_download_out["data"]["saved_path"], "/tmp/downloaded.png")

        comment_out = self.run_cmd(
            [
                "--op",
                "comment",
                "--doc",
                "dox_doc",
                "--comment",
                "请补充这段说明",
                "--selection-with-ellipsis",
                "旧内容...结束",
            ]
        )
        self.assertTrue(comment_out["ok"])
        args = comment_out["data"]["args"]
        content = args[args.index("--content") + 1]
        self.assertEqual(json.loads(content)[0]["text"], "请补充这段说明")

        section_out = self.run_cmd(
            [
                "--op",
                "section-update",
                "--doc",
                "dox_doc",
                "--section-title",
                "## 计划",
                "--section-mode",
                "replace",
                "--markdown",
                "新的章节内容",
            ]
        )
        self.assertTrue(section_out["ok"])
        section_args = section_out["data"]["args"]
        self.assertIn("replace_range", section_args)
        self.assertIn("## 计划", section_args)
        markdown = section_args[section_args.index("--markdown") + 1]
        self.assertTrue(markdown.startswith("## 计划\n\n"))

    def test_delete(self):
        out = self.run_cmd(
            ["--op", "delete", "--doc", "https://x.feishu.cn/docx/dox_delete123"]
        )
        self.assertTrue(out["ok"])
        self.assertEqual(out["data"]["deleted_doc_token"], "dox_delete123")

    def test_delete_invalid_url(self):
        out = self.run_cmd(
            ["--op", "delete", "--doc", "https://x.feishu.cn/wiki/wiki_token"]
        )
        self.assertFalse(out["ok"])
        self.assertEqual(out["error"]["code"], "validation")


if __name__ == "__main__":
    unittest.main()
