version: "3"

tasks:
  go:mod:tidy:
    summary: Runs `go mod tidy`
    internal: true
    cmds:
      - go mod tidy

  install:frontend:deps:
    summary: Install frontend dependencies
    dir: frontend
    sources:
      - package.json
      - package-lock.json
    generates:
      - node_modules
    preconditions:
      - sh: npm version
        msg: "Looks like npm isn't installed. Npm is part of the Node installer: https://nodejs.org/en/download/"
    cmds:
      - npm install

  build:frontend:
    label: build:frontend (DEV={{.DEV}})
    summary: Build the frontend project
    dir: frontend
    sources:
      - "**/*"
      - exclude: node_modules/**/*
    generates:
      - dist/**/*
    deps:
      - task: install:frontend:deps
      - task: generate:bindings
        vars:
          BUILD_FLAGS:
            ref: .BUILD_FLAGS
    cmds:
      - npm run {{.BUILD_COMMAND}} -q
    env:
      PRODUCTION: '{{if eq .DEV "true"}}false{{else}}true{{end}}'
    vars:
      BUILD_COMMAND: '{{if eq .DEV "true"}}build:dev{{else}}build{{end}}'

  frontend:vendor:puppertino:
    summary: Fetches Puppertino CSS into frontend/public for consistent mobile styling
    sources:
      - frontend/public/puppertino/puppertino.css
    generates:
      - frontend/public/puppertino/puppertino.css
    cmds:
      - |
        set -euo pipefail
        mkdir -p frontend/public/puppertino
        # If bundled Puppertino exists, prefer it. Otherwise, try to fetch, but don't fail build on error.
        if [ ! -f frontend/public/puppertino/puppertino.css ]; then
          echo "No bundled Puppertino found. Attempting to fetch from GitHub..."
          if curl -fsSL https://raw.githubusercontent.com/codedgar/Puppertino/main/dist/css/full.css -o frontend/public/puppertino/puppertino.css; then
            curl -fsSL https://raw.githubusercontent.com/codedgar/Puppertino/main/LICENSE -o frontend/public/puppertino/LICENSE || true
            echo "Puppertino CSS downloaded to frontend/public/puppertino/puppertino.css"
          else
            echo "Warning: Could not fetch Puppertino CSS. Proceeding without download since template may bundle it."
          fi
        else
          echo "Using bundled Puppertino at frontend/public/puppertino/puppertino.css"
        fi
        # Ensure index.html includes Puppertino CSS and button classes
        INDEX_HTML=frontend/index.html
        if [ -f "$INDEX_HTML" ]; then
          if ! grep -q 'href="/puppertino/puppertino.css"' "$INDEX_HTML"; then
            # Insert Puppertino link tag after style.css link
            awk '
              /href="\/style.css"\/?/ && !x { print; print "    <link rel=\"stylesheet\" href=\"/puppertino/puppertino.css\"/>"; x=1; next }1
            ' "$INDEX_HTML" > "$INDEX_HTML.tmp" && mv "$INDEX_HTML.tmp" "$INDEX_HTML"
          fi
          # Replace default .btn with Puppertino primary button classes if present
          sed -E -i'' 's/class=\"btn\"/class=\"p-btn p-prim-col\"/g' "$INDEX_HTML" || true
        fi

  generate:bindings:
    label: generate:bindings (BUILD_FLAGS={{.BUILD_FLAGS}})
    summary: Generates bindings for the frontend
    deps:
      - task: go:mod:tidy
    sources:
      - "**/*.[jt]s"
      - exclude: frontend/**/*
      - frontend/bindings/**/* # Rerun when switching between dev/production mode causes changes in output
      - "**/*.go"
      - go.mod
      - go.sum
    generates:
      - frontend/bindings/**/*
    cmds:
      - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true -ts

  generate:icons:
    summary: Generates Windows `.ico` and Mac `.icns` from an image; on macOS, `-iconcomposerinput appicon.icon -macassetdir darwin` also produces `Assets.car` from a `.icon` file (skipped on other platforms).
    dir: build
    sources:
      - "appicon.png"
      - "appicon.icon"
    generates:
      - "darwin/icons.icns"
      - "windows/icon.ico"
    cmds:
      - wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico -iconcomposerinput appicon.icon -macassetdir darwin

  dev:frontend:
    summary: Runs the frontend in development mode
    dir: frontend
    deps:
      - task: install:frontend:deps
    cmds:
      - npm run dev -- --port {{.VITE_PORT}} --strictPort

  update:build-assets:
    summary: Updates the build assets
    dir: build
    cmds:
      - wails3 update build-assets -name "{{.APP_NAME}}" -binaryname "{{.APP_NAME}}" -config config.yml -dir .

  build:server:
    summary: Builds the application in server mode (no GUI, HTTP server only)
    desc: |
      Builds the application with the server build tag enabled.
      Server mode runs as a pure HTTP server without native GUI dependencies.
      Usage: task build:server
    deps:
      - task: build:frontend
        vars:
          BUILD_FLAGS:
            ref: .BUILD_FLAGS
    cmds:
      - go build -tags server {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}-server{{exeExt}}
    vars:
      BUILD_FLAGS: "{{.BUILD_FLAGS}}"

  run:server:
    summary: Builds and runs the application in server mode
    deps:
      - task: build:server
    cmds:
      - ./{{.BIN_DIR}}/{{.APP_NAME}}-server{{exeExt}}

  build:docker:
    summary: Builds a Docker image for server mode deployment
    desc: |
      Creates a minimal Docker image containing the server mode binary.
      The image is based on distroless for security and small size.
      Usage: task build:docker [TAG=myapp:latest]
    cmds:
      - docker build -t {{.TAG | default (printf "%s:latest" .APP_NAME)}} -f build/docker/Dockerfile.server .
    vars:
      TAG: "{{.TAG}}"
    preconditions:
      - sh: docker info > /dev/null 2>&1
        msg: "Docker is required. Please install Docker first."
      - sh: test -f build/docker/Dockerfile.server
        msg: "Dockerfile.server not found. Run 'wails3 update build-assets' to generate it."

  run:docker:
    summary: Builds and runs the Docker image
    desc: |
      Builds the Docker image and runs it, exposing port 8080.
      Usage: task run:docker [TAG=myapp:latest] [PORT=8080]
      Note: The internal container port is always 8080. The PORT variable
      only changes the host port mapping. Ensure your app uses port 8080
      or modify the Dockerfile to match your ServerOptions.Port setting.
    deps:
      - task: build:docker
        vars:
          TAG:
            ref: .TAG
    cmds:
      - docker run --rm -p {{.PORT | default "8080"}}:8080 {{.TAG | default (printf "%s:latest" .APP_NAME)}}
    vars:
      TAG: "{{.TAG}}"
      PORT: "{{.PORT}}"

  setup:docker:
    summary: Builds Docker image for cross-compilation (~800MB download)
    desc: |
      Builds the Docker image needed for cross-compiling to any platform.
      Run this once to enable cross-platform builds from any OS.
    cmds:
      - docker build -t wails-cross -f build/docker/Dockerfile.cross build/docker/
    preconditions:
      - sh: docker info > /dev/null 2>&1
        msg: "Docker is required. Please install Docker first."

  ios:device:list:
    summary: Lists connected iOS devices (UDIDs)
    cmds:
      - xcrun xcdevice list

  ios:run:device:
    summary: Build, install, and launch on a physical iPhone using Apple tools (xcodebuild/devicectl)
    vars:
      PROJECT: "{{.PROJECT}}" # e.g., build/ios/xcode/<YourProject>.xcodeproj
      SCHEME: "{{.SCHEME}}" # e.g., ios.dev
      CONFIG: '{{.CONFIG | default "Debug"}}'
      DERIVED: '{{.DERIVED | default "build/ios/DerivedData"}}'
      UDID: "{{.UDID}}" # from `task ios:device:list`
      BUNDLE_ID: "{{.BUNDLE_ID}}" # e.g., com.yourco.wails.ios.dev
      TEAM_ID: "{{.TEAM_ID}}" # optional, if your project is not already set up for signing
    preconditions:
      - sh: xcrun -f xcodebuild
        msg: "xcodebuild not found. Please install Xcode."
      - sh: xcrun -f devicectl
        msg: "devicectl not found. Please update to Xcode 15+ (which includes devicectl)."
      - sh: test -n '{{.PROJECT}}'
        msg: "Set PROJECT to your .xcodeproj path (e.g., PROJECT=build/ios/xcode/App.xcodeproj)."
      - sh: test -n '{{.SCHEME}}'
        msg: "Set SCHEME to your app scheme (e.g., SCHEME=ios.dev)."
      - sh: test -n '{{.UDID}}'
        msg: "Set UDID to your device UDID (see: task ios:device:list)."
      - sh: test -n '{{.BUNDLE_ID}}'
        msg: "Set BUNDLE_ID to your app's bundle identifier (e.g., com.yourco.wails.ios.dev)."
    cmds:
      - |
        set -euo pipefail
        echo "Building for device: UDID={{.UDID}} SCHEME={{.SCHEME}} PROJECT={{.PROJECT}}"
        XCB_ARGS=(
          -project "{{.PROJECT}}"
          -scheme "{{.SCHEME}}"
          -configuration "{{.CONFIG}}"
          -destination "id={{.UDID}}"
          -derivedDataPath "{{.DERIVED}}"
          -allowProvisioningUpdates
          -allowProvisioningDeviceRegistration
        )
        # Optionally inject signing identifiers if provided
        if [ -n '{{.TEAM_ID}}' ]; then XCB_ARGS+=(DEVELOPMENT_TEAM={{.TEAM_ID}}); fi
        if [ -n '{{.BUNDLE_ID}}' ]; then XCB_ARGS+=(PRODUCT_BUNDLE_IDENTIFIER={{.BUNDLE_ID}}); fi
        xcodebuild "${XCB_ARGS[@]}" build | xcpretty || true
        # If xcpretty isn't installed, run without it
        if [ "${PIPESTATUS[0]}" -ne 0 ]; then
          xcodebuild "${XCB_ARGS[@]}" build
        fi
        # Find built .app
        APP_PATH=$(find "{{.DERIVED}}/Build/Products" -type d -name "*.app" -maxdepth 3 | head -n 1)
        if [ -z "$APP_PATH" ]; then
          echo "Could not locate built .app under {{.DERIVED}}/Build/Products" >&2
          exit 1
        fi
        echo "Installing: $APP_PATH"
        xcrun devicectl device install app --device "{{.UDID}}" "$APP_PATH"
        echo "Launching: {{.BUNDLE_ID}}"
        xcrun devicectl device process launch --device "{{.UDID}}" --stderr console --stdout console "{{.BUNDLE_ID}}"
