#!/bin/bash
# 创建新的 SDK 包
#
# 流程：
#   1. flutter create --template=plugin  生成完整 Flutter 插件骨架（含原生代码）
#   2. mason make clean_plugin_sdk       覆盖写入 Facade+Wiring 架构
#   3. 修正 pubspec.yaml                 注入 resolution: workspace + 统一版本约束
#   4. 更新 IDE 配置                     .iml + modules.xml
#   5. dart pub get
#
# 用法：
#   melos run new:sdk -- push        # 创建 packages/push_sdk/
#   melos run new:sdk -- push_sdk    # 同上，_sdk 后缀可省略

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"

if [[ $# -eq 0 ]]; then
  echo "Usage: melos run new:sdk -- <name>"
  echo "Example: melos run new:sdk -- push"
  exit 1
fi

INPUT="$1"
BASE_NAME="${INPUT%_sdk}"
PKG_NAME="${BASE_NAME}_sdk"

PASCAL_NAME=$(python3 -c "
parts = '${BASE_NAME}'.split('_')
print(''.join(p.capitalize() for p in parts))
")

PKG_DIR="$ROOT_DIR/packages/$PKG_NAME"

if [[ -d "$PKG_DIR" ]]; then
  echo "Error: packages/$PKG_NAME already exists"
  exit 1
fi

# mason 路径解析：PATH 里找不到时 fallback 到 pub-cache 绝对路径
# setup.sh 把 mason 装到 ~/.pub-cache/bin，需要重启终端 PATH 才生效
if command -v mason &> /dev/null; then
  MASON_CMD="mason"
elif [[ -x "$HOME/.pub-cache/bin/mason" ]]; then
  MASON_CMD="$HOME/.pub-cache/bin/mason"
else
  echo "Error: mason not found."
  echo "Run 'bash scripts/setup.sh' to install required tools."
  exit 1
fi

# ---- 失败回滚 ----
# set -e 触发退出时自动还原：删目录、撤 workspace 条目、撤 modules.xml 条目
_cleanup_on_error() {
  local code=$?
  [[ $code -eq 0 ]] && return 0
  trap - EXIT  # 防止函数内部错误触发递归
  echo ""
  echo "Error (exit $code). Rolling back..."
  [[ -d "$PKG_DIR" ]] && { rm -rf "$PKG_DIR"; echo "  Removed packages/$PKG_NAME"; }
  python3 - "$ROOT_DIR/pubspec.yaml" "$PKG_NAME" << 'PY_ROLLBACK'
import sys
path, pkg = sys.argv[1], sys.argv[2]
with open(path) as f: lines = f.readlines()
lines = [l for l in lines if l != f'  - packages/{pkg}\n']
with open(path, 'w') as f: f.writelines(lines)
PY_ROLLBACK
  python3 - "$ROOT_DIR/.idea/modules.xml" "$PKG_NAME" << 'PY_ROLLBACK'
import sys, re
path, pkg = sys.argv[1], sys.argv[2]
with open(path) as f: content = f.read()
content = re.sub(rf'\s*<module[^>]*packages/{re.escape(pkg)}/[^>]*/>\n?', '', content)
with open(path, 'w') as f: f.write(content)
PY_ROLLBACK
  echo "  Rollback complete. Re-run after fixing the issue."
}
trap _cleanup_on_error EXIT

echo "Creating packages/$PKG_NAME  (${PASCAL_NAME}SdkApi)..."
echo ""

# ---- Step 1: flutter create ----
echo "[1/5] flutter create --template=plugin..."
cd "$ROOT_DIR"
flutter create \
  --template=plugin \
  --platforms=ios,android,macos,windows \
  --org com.example \
  --project-name "$PKG_NAME" \
  "packages/$PKG_NAME"
echo ""

# ---- Step 2: mason make ----
echo "[2/5] mason make clean_plugin_sdk (Facade+Wiring)..."
cd "$ROOT_DIR"
$MASON_CMD make clean_plugin_sdk \
  --name "$PKG_NAME" \
  --sdk_class "${PASCAL_NAME}Sdk" \
  --output-dir "packages/$PKG_NAME" \
  --on-conflict overwrite
echo ""

# ---- Step 3: 修正 pubspec.yaml ----
echo "[3/5] Patching pubspec.yaml..."
python3 - "$PKG_DIR/pubspec.yaml" "$ROOT_DIR" << 'PY'
import sys, re, os, glob

path, root_dir = sys.argv[1], sys.argv[2]
with open(path) as f:
    content = f.read()

# 从根 pubspec.yaml 读取当前 Dart 版本约束
dart_version = '3.11.0'
root_pubspec = os.path.join(root_dir, 'pubspec.yaml')
with open(root_pubspec) as f:
    root_content = f.read()
m = re.search(r'^\s*sdk:\s*\^([\d.]+)', root_content, re.MULTILINE)
if m:
    dart_version = m.group(1)

# 从已有 plugin 包读取当前 Flutter 最低版本（取最大值，避免旧包的低版本干扰）
def _ver(s):
    try:
        return tuple(int(x) for x in s.split('.'))
    except Exception:
        return (0,)

flutter_version = '3.38.4'
for pkg_pubspec in glob.glob(os.path.join(root_dir, 'packages', '*', 'pubspec.yaml')):
    with open(pkg_pubspec) as f:
        pkg_content = f.read()
    m = re.search(r"flutter:\s*'>=([^']+)'", pkg_content)
    if m and _ver(m.group(1)) > _ver(flutter_version):
        flutter_version = m.group(1)

# 1. 注入 resolution: workspace
# flutter create 新版不含 publish_to，按 publish_to → version → name 顺序降级匹配
if 'resolution: workspace' not in content:
    if re.search(r'publish_to:[^\n]*\n', content):
        content = re.sub(
            r'(publish_to:[^\n]*\n)',
            r'\1resolution: workspace\n',
            content,
        )
    elif re.search(r'^version:[^\n]*\n', content, re.MULTILINE):
        content = re.sub(
            r'(^version:[^\n]*\n)',
            r'\1resolution: workspace\n',
            content,
            flags=re.MULTILINE,
        )
    else:
        content = re.sub(
            r'(^name:[^\n]*\n)',
            r'\1resolution: workspace\n',
            content,
            flags=re.MULTILINE,
        )

# 2. 统一 Dart SDK 约束：'>=x.x.x <4.0.0' 或 ^x.x.x → 与主工程一致
# flutter create 新版直接生成 ^x.x.x，旧版生成 '>=x <y'，两种格式都处理
content = re.sub(r"sdk:\s*(?:['\"]>=[\d.]+ <[\d.]+['\"]|\^[\d.]+)", f"sdk: ^{dart_version}", content)

# 3. 统一 Flutter 最低版本：与主工程已有包一致
content = re.sub(r'flutter:\s*["\']>=[\d.]+["\']', f"flutter: '>={flutter_version}'", content)

# 4. 统一 flutter_lints 版本
content = re.sub(r"flutter_lints:\s*\^[\d.]+", "flutter_lints: ^6.0.0", content)

# 5. 注入代码生成依赖（gen / gen:watch 靠 --depends-on="build_runner" 过滤，
#    没有 build_runner 的包会被跳过，@JsonSerializable / @freezed 等注解不会生成）
code_gen_deps = {
    'build_runner': '^2.4.6',
    'json_serializable': '^6.7.1',
    'freezed': '^3.0.0',
}
# 从根 pubspec 读取实际版本（保持全局一致）
for dep, default_ver in code_gen_deps.items():
    m = re.search(rf'^\s+{re.escape(dep)}:\s*(\^[\d.]+)', root_content, re.MULTILINE)
    if m:
        code_gen_deps[dep] = m.group(1)

for dep, ver in code_gen_deps.items():
    if dep not in content:
        content = re.sub(
            r'(dev_dependencies:\n)',
            rf'\1  {dep}: {ver}\n',
            content,
        )

with open(path, 'w') as f:
    f.write(content)
PY

# example/pubspec.yaml 同步统一 Dart 版本（flutter create 生成的 example 有相同问题）
python3 - "$PKG_DIR/example/pubspec.yaml" "$ROOT_DIR" << 'PY'
import sys, re, os

path, root_dir = sys.argv[1], sys.argv[2]
if not os.path.exists(path):
    sys.exit(0)

dart_version = '3.11.0'
root_pubspec = os.path.join(root_dir, 'pubspec.yaml')
with open(root_pubspec) as f:
    root_content = f.read()
m = re.search(r'^\s*sdk:\s*\^([\d.]+)', root_content, re.MULTILINE)
if m:
    dart_version = m.group(1)

with open(path) as f:
    content = f.read()
content = re.sub(r"sdk:\s*(?:['\"]>=[\d.]+ <[\d.]+['\"]|\^[\d.]+)", f"sdk: ^{dart_version}", content)
with open(path, 'w') as f:
    f.write(content)
PY

# ---- Step 4: IDE 配置 ----
echo "[4/5] Updating IDE config..."

# .iml 文件
cat > "$PKG_DIR/melos_${PKG_NAME}.iml" << 'IML_EOF'
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
      <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
      <excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
      <excludeFolder url="file://$MODULE_DIR$/.pub" />
      <excludeFolder url="file://$MODULE_DIR$/build" />
      <excludeFolder url="file://$MODULE_DIR$/example/.dart_tool" />
      <excludeFolder url="file://$MODULE_DIR$/example/.pub" />
      <excludeFolder url="file://$MODULE_DIR$/example/build" />
    </content>
    <orderEntry type="sourceFolder" forTests="false" />
    <orderEntry type="library" name="Dart SDK" level="project" />
    <orderEntry type="library" name="Dart Packages" level="project" />
    <orderEntry type="library" name="Flutter Plugins" level="project" />
  </component>
</module>
IML_EOF

# 根 pubspec.yaml workspace
python3 - "$ROOT_DIR/pubspec.yaml" "$PKG_NAME" << 'PY'
import sys

pubspec_path, pkg_name = sys.argv[1], sys.argv[2]
with open(pubspec_path) as f:
    lines = f.readlines()

new_entry = f'  - packages/{pkg_name}\n'
if new_entry in lines:
    sys.exit(0)

last_pkg_idx = -1
in_workspace = False
for i, line in enumerate(lines):
    stripped = line.strip()
    if stripped == 'workspace:':
        in_workspace = True
    elif in_workspace and stripped.startswith('- packages/'):
        last_pkg_idx = i
    elif in_workspace and stripped and not stripped.startswith('-'):
        break

if last_pkg_idx >= 0:
    lines.insert(last_pkg_idx + 1, new_entry)

with open(pubspec_path, 'w') as f:
    f.writelines(lines)
PY

# .idea/modules.xml
python3 - "$ROOT_DIR/.idea/modules.xml" "$PKG_NAME" << 'PY'
import sys

modules_path, pkg_name = sys.argv[1], sys.argv[2]
with open(modules_path) as f:
    content = f.read()

entry = (
    f'<module fileurl="file://$PROJECT_DIR$/packages/{pkg_name}/melos_{pkg_name}.iml"'
    f' filepath="$PROJECT_DIR$/packages/{pkg_name}/melos_{pkg_name}.iml"/>'
)
if entry in content:
    sys.exit(0)

content = content.replace('    </modules>', f'{entry}\n    </modules>')
with open(modules_path, 'w') as f:
    f.write(content)
PY

# ---- Step 5: dart pub get ----
echo ""
echo "[5/5] dart pub get..."
cd "$ROOT_DIR" && dart pub get

echo ""
echo "Done. packages/$PKG_NAME is ready."
echo ""
echo "Next steps:"
echo "  1. Define API in lib/src/presentation/facade/${PKG_NAME}_api.dart"
echo "  2. Add domain entities under lib/src/domain/entities/"
echo "  3. Implement in lib/src/presentation/wiring/${PKG_NAME}_api_impl.dart"
