package sqlite

import (
	"context"
	"database/sql"
	"fmt"
	"strings"
)

// getNextChildNumber atomically increments and returns the next child counter for a parent issue.
// Uses INSERT...ON CONFLICT to ensure atomicity without explicit locking.
func (s *SQLiteStorage) getNextChildNumber(ctx context.Context, parentID string) (int, error) {
	var nextChild int
	err := s.db.QueryRowContext(ctx, `
		INSERT INTO child_counters (parent_id, last_child)
		VALUES (?, 1)
		ON CONFLICT(parent_id) DO UPDATE SET
			last_child = last_child + 1
		RETURNING last_child
	`, parentID).Scan(&nextChild)
	if err != nil {
		return 0, fmt.Errorf("failed to generate next child number for parent %s: %w", parentID, err)
	}
	return nextChild, nil
}

// GetNextChildID generates the next hierarchical child ID for a given parent
// Returns formatted ID as parentID.{counter} (e.g., bd-a3f8e9.1 or bd-a3f8e9.1.5)
// Works at any depth (max 3 levels)
func (s *SQLiteStorage) GetNextChildID(ctx context.Context, parentID string) (string, error) {
	// Validate parent exists
	var count int
	err := s.db.QueryRowContext(ctx, `SELECT COUNT(*) FROM issues WHERE id = ?`, parentID).Scan(&count)
	if err != nil {
		return "", fmt.Errorf("failed to check parent existence: %w", err)
	}
	if count == 0 {
		// Try to resurrect parent from JSONL history before failing (bd-dvd fix, bd-ar2.4)
		// Note: Using TryResurrectParent instead of TryResurrectParentChain because we're
		// already given the direct parent ID. TryResurrectParent will handle the direct parent,
		// and if the parent itself has missing ancestors, those should have been resurrected
		// when the parent was originally created.
		resurrected, resurrectErr := s.TryResurrectParent(ctx, parentID)
		if resurrectErr != nil {
			return "", fmt.Errorf("failed to resurrect parent %s: %w", parentID, resurrectErr)
		}
		if !resurrected {
			return "", fmt.Errorf("parent issue %s does not exist and could not be resurrected from JSONL history", parentID)
		}
	}
	
	// Calculate current depth by counting dots
	depth := strings.Count(parentID, ".")
	if depth >= 3 {
		return "", fmt.Errorf("maximum hierarchy depth (3) exceeded for parent %s", parentID)
	}
	
	// Get next child number atomically
	nextNum, err := s.getNextChildNumber(ctx, parentID)
	if err != nil {
		return "", err
	}
	
	// Format as parentID.counter
	childID := fmt.Sprintf("%s.%d", parentID, nextNum)
	return childID, nil
}

// ensureChildCounterUpdated ensures the child_counters table has a value for parentID
// that is at least childNum. This prevents ID collisions when children are created
// with explicit IDs (via --id flag or import) rather than GetNextChildID.
// (GH#728 fix)
func (s *SQLiteStorage) ensureChildCounterUpdated(ctx context.Context, parentID string, childNum int) error {
	_, err := s.db.ExecContext(ctx, `
		INSERT INTO child_counters (parent_id, last_child)
		VALUES (?, ?)
		ON CONFLICT(parent_id) DO UPDATE SET
			last_child = MAX(last_child, excluded.last_child)
	`, parentID, childNum)
	if err != nil {
		return fmt.Errorf("failed to update child counter for parent %s: %w", parentID, err)
	}
	return nil
}

// ensureChildCounterUpdatedWithConn is like ensureChildCounterUpdated but uses a specific
// connection for transaction consistency. (GH#728 fix)
func ensureChildCounterUpdatedWithConn(ctx context.Context, conn *sql.Conn, parentID string, childNum int) error {
	_, err := conn.ExecContext(ctx, `
		INSERT INTO child_counters (parent_id, last_child)
		VALUES (?, ?)
		ON CONFLICT(parent_id) DO UPDATE SET
			last_child = MAX(last_child, excluded.last_child)
	`, parentID, childNum)
	if err != nil {
		return fmt.Errorf("failed to update child counter for parent %s: %w", parentID, err)
	}
	return nil
}

// generateHashID moved to ids.go (bd-0702)
