#!/usr/bin/env bash
# init_go_project
# ---------------
# Pipeline que inicializa un repositorio Go completo con estructura profesional:
# cmd/app, internal/config, internal/service, pkg/version, scripts/, Makefile,
# .gitignore, README y git init.
#
# USO:
#   bash init_go_project.sh [module_path]
#
# ARGUMENTOS:
#   module_path   Path del módulo Go (opcional; default: github.com/<whoami>/<dirname>)

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

init_go_project() {
    local module_path="${1:-}"

    local project_name
    project_name="$(basename "$(pwd)")"

    if [[ -z "$module_path" ]]; then
        module_path="github.com/$(whoami)/${project_name}"
    fi

    echo "=== Inicializar Proyecto Go Completo ==="
    echo "  Proyecto: ${project_name}"
    echo "  Módulo:   ${module_path}"
    echo "  Dir:      $(pwd)"
    echo ""

    # Verificar dependencias
    if ! command -v go &>/dev/null; then
        echo "init_go_project: Go no está instalado" >&2
        return 1
    fi
    if ! command -v git &>/dev/null; then
        echo "init_go_project: git no está instalado" >&2
        return 1
    fi

    echo "Go:  $(go version)"
    echo "git: $(git --version)"
    echo ""

    # Crear estructura de carpetas
    echo "Creando estructura de carpetas..."
    mkdir -p cmd/app internal/config internal/service pkg/version scripts bin
    echo "Estructura base creada"
    echo ""

    # go mod init
    echo "Inicializando módulo Go..."
    if ! go mod init "$module_path"; then
        echo "init_go_project: falló go mod init" >&2
        return 1
    fi
    echo "go.mod creado"
    echo ""

    # Crear archivos fuente
    echo "Creando archivos fuente..."

    cat > cmd/app/main.go << GOEOF
package main

import (
	"fmt"

	"${module_path}/internal/config"
	"${module_path}/internal/service"
	"${module_path}/pkg/version"
)

func main() {
	cfg := config.Load()
	msg := service.BuildStartupMessage(cfg.AppName, version.Current())
	fmt.Println(msg)
}
GOEOF

    cat > internal/config/config.go << 'CFGEOF'
package config

import "os"

type AppConfig struct {
	AppName string
}

func Load() AppConfig {
	appName := os.Getenv("APP_NAME")
	if appName == "" {
		appName = "Go Project"
	}
	return AppConfig{AppName: appName}
}
CFGEOF

    cat > internal/service/message.go << 'SVCEOF'
package service

import "fmt"

func BuildStartupMessage(appName, appVersion string) string {
	return fmt.Sprintf("%s iniciado correctamente (version %s)", appName, appVersion)
}
SVCEOF

    cat > internal/service/message_test.go << 'TESTEOF'
package service

import "testing"

func TestBuildStartupMessage(t *testing.T) {
	result := BuildStartupMessage("MyApp", "0.1.0")
	want := "MyApp iniciado correctamente (version 0.1.0)"
	if result != want {
		t.Fatalf("resultado inesperado:\nwant: %s\ngot:  %s", want, result)
	}
}
TESTEOF

    cat > pkg/version/version.go << 'VEREOF'
package version

var value = "0.1.0"

func Current() string {
	return value
}
VEREOF

    echo "Archivos fuente creados"
    echo ""

    # Makefile
    echo "Creando Makefile..."
    cat > Makefile << 'MAKEEOF'
APP_NAME=app
CMD_PATH=./cmd/app
BIN_DIR=./bin

.PHONY: run build build-all test fmt tidy clean

run:
	go run $(CMD_PATH)

build:
	mkdir -p $(BIN_DIR)
	go build -o $(BIN_DIR)/$(APP_NAME) $(CMD_PATH)

build-all:
	bash ./scripts/build-all.sh

test:
	go test ./...

fmt:
	gofmt -w ./cmd ./internal ./pkg

tidy:
	go mod tidy

clean:
	rm -rf $(BIN_DIR)
MAKEEOF
    echo "Makefile creado"
    echo ""

    # .gitignore
    cat > .gitignore << 'IGNEOF'
bin/
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
*.out
coverage.out
.idea/
.vscode/
*.swp
*.swo
*~
.DS_Store
Thumbs.db
IGNEOF

    # README
    cat > README.md << READEOF
# ${project_name}

Repositorio Go inicializado con estructura completa.

## Uso rápido

\`\`\`bash
./scripts/run.sh
./scripts/test.sh
./scripts/build.sh
\`\`\`

## Make

\`\`\`bash
make run
make test
make build
make build-all
\`\`\`
READEOF

    # Scripts
    echo "Creando scripts..."

    cat > scripts/run.sh << 'RUNEOF'
#!/bin/bash
set -euo pipefail
go run ./cmd/app
RUNEOF

    cat > scripts/test.sh << 'TESTSHEOF'
#!/bin/bash
set -euo pipefail
go test ./...
TESTSHEOF

    cat > scripts/build.sh << 'BUILDSHEOF'
#!/bin/bash
set -euo pipefail
mkdir -p ./bin
go build -o ./bin/app ./cmd/app
echo "Binario: ./bin/app"
BUILDSHEOF

    cat > scripts/build-all.sh << 'BUILDALLEOF'
#!/bin/bash
set -euo pipefail
mkdir -p ./bin
GOOS=linux   GOARCH=amd64 go build -o ./bin/app-linux-amd64   ./cmd/app
GOOS=darwin  GOARCH=amd64 go build -o ./bin/app-darwin-amd64  ./cmd/app
GOOS=windows GOARCH=amd64 go build -o ./bin/app-windows-amd64.exe ./cmd/app
echo "Builds en ./bin"
BUILDALLEOF

    cat > scripts/lint.sh << 'LINTEOF'
#!/bin/bash
set -euo pipefail
unformatted="$(gofmt -l ./cmd ./internal ./pkg)"
if [ -n "$unformatted" ]; then
    echo "Archivos sin formato:" >&2
    echo "$unformatted" >&2
    echo "Ejecuta: make fmt" >&2
    exit 1
fi
echo "Formato OK"
LINTEOF

    chmod +x scripts/*.sh
    echo "Scripts creados"
    echo ""

    # go mod tidy
    echo "Ajustando dependencias (go mod tidy)..."
    go mod tidy
    echo "Dependencias ajustadas"
    echo ""

    # git init
    echo "Inicializando repositorio git..."
    git init >/dev/null 2>&1
    git add .
    echo "Repositorio git inicializado"
    echo ""

    echo "=== Proyecto Go creado exitosamente ==="
    echo ""
    echo "Estructura:"
    echo "  cmd/app/main.go"
    echo "  internal/config/config.go"
    echo "  internal/service/message.go + message_test.go"
    echo "  pkg/version/version.go"
    echo "  scripts/ (run, test, build, build-all, lint)"
    echo "  Makefile, go.mod, .gitignore, README.md"
    echo ""
    echo "Proximos pasos:"
    echo "  1. ./scripts/run.sh"
    echo "  2. ./scripts/test.sh"
    echo "  3. ./scripts/build-all.sh"
}

init_go_project "$@"
