#!/usr/bin/env bash
# init_kotlin_app — Scaffolder canonico de apps Android Kotlin Compose del registry.
#
# Genera la estructura canonica (MainActivity.kt, build.gradle.kts, app.md,
# Roborazzi screenshot tests), apuntando al composite build kotlin/functions/ui
# para FnTheme + FnTokens, inicializa git + repo Gitea dataforge/<name>.
#
# Uso:
#   init_kotlin_app <name> [--project <p>] [--desc "..."] [--tags "a,b"] [--package <com.foo.bar>]
#
# Por defecto sin proyecto (apps/<name>/), package = com.fnregistry.<name>.

set -euo pipefail

# Carga helpers del registry
FN_ROOT="${FN_REGISTRY_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
# shellcheck source=/dev/null
source "$FN_ROOT/bash/functions/infra/ensure_repo_synced.sh"

init_kotlin_app() {
    local name=""
    local project=""
    local desc=""
    local tags=""
    local pkg_id=""

    while [[ $# -gt 0 ]]; do
        case "$1" in
            --project) project="$2"; shift 2 ;;
            --desc)    desc="$2";    shift 2 ;;
            --tags)    tags="$2";    shift 2 ;;
            --package) pkg_id="$2";  shift 2 ;;
            -*) echo "init_kotlin_app: flag desconocido: $1" >&2; return 2 ;;
            *)  if [[ -z "$name" ]]; then name="$1"; else
                    echo "init_kotlin_app: argumento extra: $1" >&2; return 2
                fi
                shift ;;
        esac
    done

    if [[ -z "$name" ]]; then
        echo "init_kotlin_app: se requiere <name>" >&2
        echo "Uso: init_kotlin_app <name> [--project <p>] [--desc \"...\"] [--tags \"a,b\"] [--package <com.foo.bar>]" >&2
        return 2
    fi

    # Validar snake_case
    if [[ ! "$name" =~ ^[a-z][a-z0-9_]*$ ]]; then
        echo "init_kotlin_app: nombre '$name' debe ser snake_case (solo letras minusculas, digitos y _)" >&2
        return 2
    fi

    [[ -z "$desc" ]]   && desc="App Android Kotlin Compose"
    [[ -z "$pkg_id" ]] && pkg_id="com.fnregistry.$name"

    # Resolver dir destino
    local rel_dir abs_dir
    if [[ -n "$project" ]]; then
        if [[ ! -f "$FN_ROOT/projects/$project/project.md" ]]; then
            echo "init_kotlin_app: proyecto '$project' no existe (falta projects/$project/project.md)" >&2
            return 1
        fi
        rel_dir="projects/$project/apps/$name"
    else
        rel_dir="apps/$name"
    fi
    abs_dir="$FN_ROOT/$rel_dir"

    if [[ -e "$abs_dir" ]]; then
        echo "init_kotlin_app: $rel_dir ya existe" >&2
        return 1
    fi

    # Convertir package id a path (com.fnregistry.my_app -> com/fnregistry/my_app)
    local pkg_path
    pkg_path="$(echo "$pkg_id" | tr '.' '/')"

    # Calcular path relativo al composite build de kotlin/functions/ui
    # Desde apps/<name>/          -> ../../kotlin/functions/ui
    # Desde projects/<p>/apps/<n> -> ../../../../kotlin/functions/ui
    local ui_rel_path
    if [[ -n "$project" ]]; then
        ui_rel_path="../../../../kotlin/functions/ui"
    else
        ui_rel_path="../../kotlin/functions/ui"
    fi

    # ---- Crear estructura de directorios ----
    mkdir -p "$abs_dir/app/src/main/kotlin/$pkg_path"
    mkdir -p "$abs_dir/app/src/main/res/values"
    mkdir -p "$abs_dir/app/src/test/kotlin/$pkg_path"
    mkdir -p "$abs_dir/app/src/androidTest/kotlin/$pkg_path"
    mkdir -p "$abs_dir/gradle/wrapper"

    echo "init_kotlin_app: creando $rel_dir ..."

    # ---- settings.gradle.kts ----
    cat > "$abs_dir/settings.gradle.kts" <<EOF
pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
rootProject.name = "$name"
include(":app")

// Composite build: FnTheme + FnTokens desde el registry
includeBuild("$ui_rel_path") {
    dependencySubstitution {
        substitute(module("fn.compose:ui")).using(project(":"))
    }
}
EOF

    # ---- build.gradle.kts (raiz) ----
    cat > "$abs_dir/build.gradle.kts" <<'EOF'
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    id("com.android.application") version "8.4.0" apply false
    id("org.jetbrains.kotlin.android") version "1.9.22" apply false
}
EOF

    # ---- app/build.gradle.kts ----
    cat > "$abs_dir/app/build.gradle.kts" <<EOF
plugins {
    id("com.android.application") version "8.4.0"
    id("org.jetbrains.kotlin.android") version "1.9.22"
    id("io.github.takahirom.roborazzi") version "1.20.0"
}

android {
    namespace = "$pkg_id"
    compileSdk = 34

    defaultConfig {
        applicationId = "$pkg_id"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "0.1.0"
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildFeatures {
        compose = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.8"
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget = "17"
    }
    testOptions {
        unitTests {
            isIncludeAndroidResources = true
            all {
                it.systemProperty("robolectric.graphicsMode", "NATIVE")
            }
        }
    }
}

dependencies {
    implementation("androidx.activity:activity-compose:1.8.2")
    implementation(platform("androidx.compose:compose-bom:2024.02.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.material3:material3")
    implementation("androidx.compose.ui:ui-tooling-preview")
    debugImplementation("androidx.compose.ui:ui-tooling")
    // FnTheme + FnTokens via composite build
    implementation("fn.compose:ui")

    testImplementation("junit:junit:4.13.2")
    testImplementation("org.robolectric:robolectric:4.11.1")
    testImplementation("androidx.compose.ui:ui-test-junit4")
    testImplementation("io.github.takahirom.roborazzi:roborazzi:1.20.0")
    testImplementation("io.github.takahirom.roborazzi:roborazzi-compose:1.20.0")
    testImplementation("io.github.takahirom.roborazzi:roborazzi-junit-rule:1.20.0")
    androidTestImplementation(platform("androidx.compose:compose-bom:2024.02.00"))
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    debugImplementation("androidx.compose.ui:ui-test-manifest")
}
EOF

    # ---- gradle.properties ----
    cat > "$abs_dir/gradle.properties" <<'EOF'
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
android.useAndroidX=true
kotlin.code.style=official
android.nonTransitiveRClass=true
EOF

    # ---- gradle/wrapper/gradle-wrapper.properties ----
    cat > "$abs_dir/gradle/wrapper/gradle-wrapper.properties" <<'EOF'
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
EOF

    # ---- gradlew + wrapper jar (vendored real wrapper) ----
    local tmpl_wrapper="$FN_ROOT/bash/functions/pipelines/templates/kotlin/wrapper"
    if [[ -f "$tmpl_wrapper/gradlew" && -f "$tmpl_wrapper/gradle-wrapper.jar" ]]; then
        cp "$tmpl_wrapper/gradlew" "$abs_dir/gradlew"
        cp "$tmpl_wrapper/gradle-wrapper.jar" "$abs_dir/gradle/wrapper/gradle-wrapper.jar"
        chmod +x "$abs_dir/gradlew"
    else
        echo "init_kotlin_app: WARN templates/kotlin/wrapper missing, fallback gradlew stub"
        cat > "$abs_dir/gradlew" <<'EOF'
#!/usr/bin/env bash
echo "gradlew stub — install gradle wrapper or replace with real one" >&2
exit 2
EOF
        chmod +x "$abs_dir/gradlew"
    fi

    # ---- local.properties (Android SDK location, gitignored, per-machine) ----
    local sdk_path="${ANDROID_SDK_DIR:-$HOME/android-sdk}"
    if [[ ! -d "$sdk_path" ]] && [[ -d "$HOME/Android/Sdk" ]]; then
        sdk_path="$HOME/Android/Sdk"
    fi
    cat > "$abs_dir/local.properties" <<EOF
# Auto-generated by init_kotlin_app. Per-machine, gitignored.
sdk.dir=$sdk_path
EOF

    # ---- AndroidManifest.xml ----
    cat > "$abs_dir/app/src/main/AndroidManifest.xml" <<EOF
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        android:allowBackup="true"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@android:style/Theme.Material.Light.NoActionBar">

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
EOF

    # ---- res/values/strings.xml ----
    cat > "$abs_dir/app/src/main/res/values/strings.xml" <<EOF
<resources>
    <string name="app_name">$name</string>
</resources>
EOF

    # ---- MainActivity.kt ----
    cat > "$abs_dir/app/src/main/kotlin/$pkg_path/MainActivity.kt" <<EOF
package $pkg_id

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import fn.compose.theme.FnTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            FnTheme {
                Surface(modifier = Modifier.fillMaxSize()) {
                    Text("$name ready")
                }
            }
        }
    }
}
EOF

    # ---- ExampleScreenshotTest.kt (Roborazzi) ----
    cat > "$abs_dir/app/src/test/kotlin/$pkg_path/ExampleScreenshotTest.kt" <<EOF
package $pkg_id

import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onRoot
import com.github.takahirom.roborazzi.captureRoboImage
import fn.compose.theme.FnTheme
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.GraphicsMode

@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
class ExampleScreenshotTest {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun screenshotFnThemeSurface() {
        composeTestRule.setContent {
            FnTheme {
                Surface {
                    Text("$name screenshot")
                }
            }
        }
        composeTestRule.onRoot().captureRoboImage("src/test/snapshots/images/${name}_smoke.png")
    }
}
EOF

    # ---- MainActivityTest.kt (instrumented) ----
    cat > "$abs_dir/app/src/androidTest/kotlin/$pkg_path/MainActivityTest.kt" <<EOF
package $pkg_id

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class MainActivityTest {

    @get:Rule
    val composeTestRule = createAndroidComposeRule<MainActivity>()

    @Test
    fun appLaunchesAndShowsReadyText() {
        composeTestRule
            .onNodeWithText("$name ready")
            .assertIsDisplayed()
    }
}
EOF

    # ---- app.md frontmatter ----
    local repo_url="https://gitea.organic-machine.com/dataforge/$name"
    local tags_yaml="[kotlin, compose, android]"
    if [[ -n "$tags" ]]; then
        tags_yaml="[$(echo "$tags" | sed 's/,/, /g'), kotlin, compose, android]"
    fi

    cat > "$abs_dir/app.md" <<EOF
---
name: $name
domain: tools
description: "$desc"
tags: $tags_yaml
lang: kt
framework: compose
entry_point: "app/src/main/kotlin/$pkg_path/MainActivity.kt"
dir_path: "$rel_dir"
repo_url: "$repo_url"
uses_functions:
  - fn_theme_kt_ui
  - fn_tokens_kt_ui
uses_types: []
e2e_checks:
  - id: unit
    cmd: "fn run gradle_unit_test_bash_infra $rel_dir"
    timeout_s: 240
  - id: screenshot
    cmd: "fn run gradle_screenshot_test_bash_infra $rel_dir"
    timeout_s: 240
  - id: build
    cmd: "fn run gradle_assemble_debug_bash_infra $rel_dir"
    timeout_s: 360
  - id: emu_start
    cmd: "fn run android_emulator_start_bash_infra Medium_Phone_API_35"
    timeout_s: 240
  - id: instrumented
    cmd: "fn run gradle_instrumented_test_bash_infra $rel_dir"
    timeout_s: 600
  - id: emu_stop
    cmd: "fn run android_emulator_stop_bash_infra"
    severity: warning
    timeout_s: 30
---

# $name

$desc

## Build

\`\`\`bash
fn run gradle_assemble_debug_bash_infra $rel_dir
\`\`\`

## Tests unitarios + Roborazzi screenshots

\`\`\`bash
fn run gradle_unit_test_bash_infra $rel_dir
fn run gradle_screenshot_test_bash_infra $rel_dir
\`\`\`

## Tests instrumentados (requiere emulador)

\`\`\`bash
fn run android_emulator_start_bash_infra Medium_Phone_API_35
fn run gradle_instrumented_test_bash_infra $rel_dir
fn run android_emulator_stop_bash_infra
\`\`\`

## Package

\`$pkg_id\`

## FnTheme

La app usa FnTheme y FnTokens via composite build en \`kotlin/functions/ui\`.
Para cambiar colores o tipografia, editar el modulo del registry.
EOF

    # ---- .gitignore ----
    cat > "$abs_dir/.gitignore" <<'EOF'
.gradle/
build/
local.properties
*.iml
.idea/
captures/
.externalNativeBuild/
.cxx/
*.apk
*.aab
# NOTE: app/src/test/snapshots/ is committed (Roborazzi goldens are test refs).
EOF

    # ---- README.md ----
    cat > "$abs_dir/README.md" <<EOF
# $name

$desc

Generado con \`init_kotlin_app\` del registry fn_registry.

## Requisitos

- Android SDK 34
- JDK 17
- Gradle 8.6 (via wrapper)
- \`kotlin/functions/ui\` modulo del registry (composite build)

## Build rapido

\`\`\`bash
fn run gradle_assemble_debug_bash_infra $rel_dir
\`\`\`
EOF

    # ---- Git + Gitea ----
    if [[ -n "${GITEA_URL:-}" && -n "${GITEA_TOKEN:-}" ]]; then
        ensure_repo_synced "$abs_dir" "dataforge" "$name" "master" \
            "feat: scaffold $name via init_kotlin_app" || \
            echo "init_kotlin_app: warning — ensure_repo_synced fallo, repo no creado" >&2
    else
        echo "init_kotlin_app: GITEA_URL/GITEA_TOKEN no seteados, omitiendo creacion de repo Gitea" >&2
        (cd "$abs_dir" && git init -b master >/dev/null 2>&1 || git init >/dev/null 2>&1 \
            && git add -A \
            && git commit -m "feat: scaffold $name via init_kotlin_app" --quiet)
    fi

    # ---- fn index si hay proyecto ----
    if [[ -n "$project" && -x "$FN_ROOT/fn" ]]; then
        (cd "$FN_ROOT" && ./fn index >/dev/null 2>&1) || \
            echo "init_kotlin_app: warning — fn index fallo" >&2
    fi

    echo ""
    echo "init_kotlin_app: $rel_dir creada"
    echo ""
    echo "  Archivos:"
    echo "    $rel_dir/settings.gradle.kts"
    echo "    $rel_dir/app/build.gradle.kts"
    echo "    $rel_dir/app/src/main/kotlin/$pkg_path/MainActivity.kt"
    echo "    $rel_dir/app/src/test/kotlin/$pkg_path/ExampleScreenshotTest.kt"
    echo "    $rel_dir/app/src/androidTest/kotlin/$pkg_path/MainActivityTest.kt"
    echo "    $rel_dir/app.md"
    echo ""
    echo "  Pasos siguientes:"
    echo "    fn run gradle_unit_test_bash_infra $rel_dir"
    echo "    fn run gradle_screenshot_test_bash_infra $rel_dir"
    echo "    fn run gradle_assemble_debug_bash_infra $rel_dir"
    echo ""
    echo "  Para tests instrumentados (emulador):"
    echo "    fn run android_emulator_start_bash_infra Medium_Phone_API_35"
    echo "    fn run gradle_instrumented_test_bash_infra $rel_dir"
    echo "    fn run android_emulator_stop_bash_infra"
    echo ""
    echo "  Package: $pkg_id"
    echo "  FnTheme composite: $ui_rel_path"
}

# Permitir invocacion directa via 'fn run init_kotlin_app ...'
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    init_kotlin_app "$@"
fi
