package core

import (
	"testing"
)

func TestDagParse(t *testing.T) {
	t.Run("parsea DAG simple con steps y depends", func(t *testing.T) {
		data := []byte(`
name: example
description: Example workflow
steps:
  - name: hello
    command: echo "Hello!"
  - name: list_files
    command: ls -la /tmp
    depends:
      - hello
`)
		dag, err := DagParse(data)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if dag.Name != "example" {
			t.Errorf("Name: got %q, want %q", dag.Name, "example")
		}
		if len(dag.Steps) != 2 {
			t.Fatalf("Steps: got %d, want 2", len(dag.Steps))
		}
		if dag.Steps[0].Name != "hello" {
			t.Errorf("Steps[0].Name: got %q, want %q", dag.Steps[0].Name, "hello")
		}
		if dag.Steps[1].Name != "list_files" {
			t.Errorf("Steps[1].Name: got %q, want %q", dag.Steps[1].Name, "list_files")
		}
		if len(dag.Steps[1].Depends) != 1 || dag.Steps[1].Depends[0] != "hello" {
			t.Errorf("Steps[1].Depends: got %v, want [hello]", dag.Steps[1].Depends)
		}
	})

	t.Run("parsea schedule como string y como lista", func(t *testing.T) {
		// Schedule as string.
		dataStr := []byte(`
name: dag-string-schedule
schedule: "0 9 * * 5"
steps:
  - name: step1
    command: echo ok
`)
		dagStr, err := DagParse(dataStr)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if len(dagStr.Schedule) != 1 || dagStr.Schedule[0] != "0 9 * * 5" {
			t.Errorf("Schedule (string): got %v, want [\"0 9 * * 5\"]", dagStr.Schedule)
		}

		// Schedule as list.
		dataList := []byte(`
name: dag-list-schedule
schedule:
  - "0 9 * * *"
  - "0 18 * * *"
steps:
  - name: step1
    command: echo ok
`)
		dagList, err := DagParse(dataList)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if len(dagList.Schedule) != 2 {
			t.Fatalf("Schedule (list): got %d items, want 2", len(dagList.Schedule))
		}
		if dagList.Schedule[0] != "0 9 * * *" {
			t.Errorf("Schedule[0]: got %q, want %q", dagList.Schedule[0], "0 9 * * *")
		}
		if dagList.Schedule[1] != "0 18 * * *" {
			t.Errorf("Schedule[1]: got %q, want %q", dagList.Schedule[1], "0 18 * * *")
		}
	})

	t.Run("parsea env en formato lista de maps", func(t *testing.T) {
		data := []byte(`
name: dag-env
env:
  - PROJECT_DIR: /home/lucas/analysis
  - PYTHON: /home/lucas/.venv/bin/python
steps:
  - name: step1
    command: echo ${PROJECT_DIR}
`)
		dag, err := DagParse(data)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if dag.Env["PROJECT_DIR"] != "/home/lucas/analysis" {
			t.Errorf("Env[PROJECT_DIR]: got %q, want %q", dag.Env["PROJECT_DIR"], "/home/lucas/analysis")
		}
		if dag.Env["PYTHON"] != "/home/lucas/.venv/bin/python" {
			t.Errorf("Env[PYTHON]: got %q, want %q", dag.Env["PYTHON"], "/home/lucas/.venv/bin/python")
		}
	})

	t.Run("parsea handler_on y handlers como alias", func(t *testing.T) {
		// handler_on with single step object.
		dataHandlerOn := []byte(`
name: dag-handler-on
handler_on:
  failure:
    command: echo "FALLO"
steps:
  - name: step1
    command: echo hello
`)
		dagHO, err := DagParse(dataHandlerOn)
		if err != nil {
			t.Fatalf("unexpected error (handler_on): %v", err)
		}
		if len(dagHO.HandlerOn.Failure) != 1 {
			t.Fatalf("HandlerOn.Failure: got %d steps, want 1", len(dagHO.HandlerOn.Failure))
		}
		if dagHO.HandlerOn.Failure[0].Command != `echo "FALLO"` {
			t.Errorf("HandlerOn.Failure[0].Command: got %q", dagHO.HandlerOn.Failure[0].Command)
		}

		// handlers alias with list of steps.
		dataHandlers := []byte(`
name: dag-handlers
handlers:
  failure:
    - name: mark_as_failed
      command: echo "FAILED"
  success:
    - name: notify
      command: echo "OK"
steps:
  - name: step1
    command: echo hello
`)
		dagH, err := DagParse(dataHandlers)
		if err != nil {
			t.Fatalf("unexpected error (handlers): %v", err)
		}
		if len(dagH.HandlerOn.Failure) != 1 || dagH.HandlerOn.Failure[0].Name != "mark_as_failed" {
			t.Errorf("HandlerOn.Failure: got %v", dagH.HandlerOn.Failure)
		}
		if len(dagH.HandlerOn.Success) != 1 || dagH.HandlerOn.Success[0].Name != "notify" {
			t.Errorf("HandlerOn.Success: got %v", dagH.HandlerOn.Success)
		}
	})

	t.Run("parsea continue_on y working_dir a nivel step", func(t *testing.T) {
		data := []byte(`
name: dag-step-options
steps:
  - id: ingest
    description: Procesar archivos
    working_dir: /home/lucas/project
    command: ./bin/ingest
    continue_on:
      failure: true
  - id: informe
    command: python /tmp/script.py
    depends: [ingest]
`)
		dag, err := DagParse(data)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if len(dag.Steps) != 2 {
			t.Fatalf("Steps: got %d, want 2", len(dag.Steps))
		}
		step0 := dag.Steps[0]
		if step0.ID != "ingest" {
			t.Errorf("Steps[0].ID: got %q, want %q", step0.ID, "ingest")
		}
		if step0.Dir != "/home/lucas/project" {
			t.Errorf("Steps[0].Dir: got %q, want %q", step0.Dir, "/home/lucas/project")
		}
		if !step0.ContinueOn.Failure {
			t.Errorf("Steps[0].ContinueOn.Failure: got false, want true")
		}
		step1 := dag.Steps[1]
		if len(step1.Depends) != 1 || step1.Depends[0] != "ingest" {
			t.Errorf("Steps[1].Depends: got %v, want [ingest]", step1.Depends)
		}
	})

	t.Run("parsea continue_on.exit_code y retry_policy", func(t *testing.T) {
		data := []byte(`
name: dag-retry
steps:
  - name: backup
    command: ./backup.sh
    continue_on:
      exit_code: [4, 5]
    retry_policy:
      limit: 3
      interval_sec: 10
`)
		dag, err := DagParse(data)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if len(dag.Steps) != 1 {
			t.Fatalf("Steps: got %d, want 1", len(dag.Steps))
		}
		step := dag.Steps[0]
		if len(step.ContinueOn.ExitCodes) != 2 || step.ContinueOn.ExitCodes[0] != 4 || step.ContinueOn.ExitCodes[1] != 5 {
			t.Errorf("ContinueOn.ExitCodes: got %v, want [4 5]", step.ContinueOn.ExitCodes)
		}
		if step.RetryPolicy.Limit != 3 {
			t.Errorf("RetryPolicy.Limit: got %d, want 3", step.RetryPolicy.Limit)
		}
		if step.RetryPolicy.IntervalSec != 10 {
			t.Errorf("RetryPolicy.IntervalSec: got %d, want 10", step.RetryPolicy.IntervalSec)
		}
	})

	t.Run("parsea step con function id y args", func(t *testing.T) {
		data := []byte(`
name: dag-function
steps:
  - name: foo
    function: audit_capability_groups_go_infra
    args:
      - --json
`)
		dag, err := DagParse(data)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if len(dag.Steps) != 1 {
			t.Fatalf("Steps: got %d, want 1", len(dag.Steps))
		}
		if dag.Steps[0].Function != "audit_capability_groups_go_infra" {
			t.Errorf("Steps[0].Function: got %q, want %q", dag.Steps[0].Function, "audit_capability_groups_go_infra")
		}
		if len(dag.Steps[0].Args) != 1 || dag.Steps[0].Args[0] != "--json" {
			t.Errorf("Steps[0].Args: got %v, want [--json]", dag.Steps[0].Args)
		}
	})

	t.Run("parsea type graph", func(t *testing.T) {
		data := []byte(`
name: dag-graph
type: graph
tags: [finanzas, semanal]
steps:
  - name: step1
    command: echo a
  - name: step2
    command: echo b
    depends: [step1]
`)
		dag, err := DagParse(data)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if dag.Type != "graph" {
			t.Errorf("Type: got %q, want %q", dag.Type, "graph")
		}
		if len(dag.Tags) != 2 {
			t.Errorf("Tags: got %v, want [finanzas semanal]", dag.Tags)
		}
	})
}
