package python

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
)

type Python struct {
	// Add fields as needed for Python analysis
}

// Name returns the name of the Python technology stack.
func (p *Python) Name() string {
	return "Python"
}

// Analyze analyzes the codebase and returns a guessed technology stack for Python.
func (p *Python) Analyze(codebasePath string) (bool, error) {
	// Verify if the codebasePath is valid
	if codebasePath == "" {
		return false, fmt.Errorf("codebase path is empty")
	}

	// Check if codebase exists
	if _, err := os.Stat(codebasePath); os.IsNotExist(err) {
		return false, fmt.Errorf("codebase path does not exist: %s", codebasePath)
	}

	// Placeholder: Check for a common Python file like requirements.txt or a .py file
	// This is a very basic check and should be expanded.
	foundPythonIndicator := false
	if _, err := os.Stat(filepath.Join(codebasePath, "requirements.txt")); err == nil {
		foundPythonIndicator = true
	}

	// You might want to walk the directory for .py files if requirements.txt isn't found
	if !foundPythonIndicator {
		walkErr := filepath.WalkDir(codebasePath, func(path string, d os.DirEntry, err error) error {
			if err != nil {
				return err
			}
			if !d.IsDir() && strings.HasSuffix(d.Name(), ".py") {
				foundPythonIndicator = true
				return filepath.SkipDir // Found a .py file, no need to search further in this dir for this check
			}
			return nil
		})
		if walkErr != nil {
			// Log or handle walk error, but it might not be fatal for analysis
			fmt.Printf("Error walking directory for python files: %v\n", walkErr)
		}
	}

	return foundPythonIndicator, nil
}

type PythonProjectAnalysis struct {
	PythonVersion string   `json:"python_version"`
	Framework     string   `json:"framework"`
	UsePoetry     bool     `json:"use_poetry"`
	UsePipenv     bool     `json:"use_pipenv"`
	Entrypoint    string   `json:"entrypoint"`
	Port          int      `json:"port"`
	Packages      []string `json:"packages"`
	SystemDeps    []string `json:"system_deps"`
	StartCommand  string   `json:"start_command"`
}

func (p *Python) analyzePythonProject(codebasePath string) (*PythonProjectAnalysis, error) {
	analysis := &PythonProjectAnalysis{
		Port: 8000, // Default for Python
	}

	// Check for Poetry
	pyprojectPath := filepath.Join(codebasePath, "pyproject.toml")
	if p.fileExists(pyprojectPath) {
		analysis.UsePoetry = true
		// Could parse pyproject.toml for more details
	}

	// Check for Pipenv
	pipfilePath := filepath.Join(codebasePath, "Pipfile")
	if p.fileExists(pipfilePath) {
		analysis.UsePipenv = true
	}

	// Read requirements.txt if it exists
	reqPath := filepath.Join(codebasePath, "requirements.txt")
	if content, err := os.ReadFile(reqPath); err == nil {
		lines := strings.Split(string(content), "\n")
		for _, line := range lines {
			line = strings.TrimSpace(line)
			if line != "" && !strings.HasPrefix(line, "#") {
				// Extract package name (before == or >=)
				parts := strings.FieldsFunc(line, func(r rune) bool {
					return r == '=' || r == '>' || r == '<' || r == '!' || r == '~'
				})
				if len(parts) > 0 {
					analysis.Packages = append(analysis.Packages, parts[0])
				}
			}
		}
	}

	// Detect framework from packages
	for _, pkg := range analysis.Packages {
		switch {
		case strings.Contains(pkg, "fastapi"):
			analysis.Framework = "fastapi"
		case strings.Contains(pkg, "flask"):
			analysis.Framework = "flask"
		case strings.Contains(pkg, "django"):
			analysis.Framework = "django"
		case strings.Contains(pkg, "tornado"):
			analysis.Framework = "tornado"
		case strings.Contains(pkg, "sanic"):
			analysis.Framework = "sanic"
		}
	}

	// Detect entrypoint
	entrypoints := []string{"main.py", "app.py", "server.py", "run.py", "wsgi.py"}
	for _, ep := range entrypoints {
		if p.fileExists(filepath.Join(codebasePath, ep)) {
			analysis.Entrypoint = ep
			break
		}
	}
	if analysis.Entrypoint == "" {
		if analysis.Framework == "django" && p.fileExists(filepath.Join(codebasePath, "manage.py")) {
			analysis.Entrypoint = "manage.py"
		} else {
			analysis.Entrypoint = "app.py" // Default
		}
	}

	// Check for system dependencies
	for _, pkg := range analysis.Packages {
		switch {
		case strings.Contains(pkg, "psycopg2") || strings.Contains(pkg, "pg"):
			analysis.SystemDeps = append(analysis.SystemDeps, "libpq-dev")
		case strings.Contains(pkg, "mysql"):
			analysis.SystemDeps = append(analysis.SystemDeps, "default-libmysqlclient-dev")
		case strings.Contains(pkg, "pillow") || strings.Contains(pkg, "PIL"):
			analysis.SystemDeps = append(analysis.SystemDeps, "libjpeg-dev", "zlib1g-dev")
		case strings.Contains(pkg, "lxml"):
			analysis.SystemDeps = append(analysis.SystemDeps, "libxml2-dev", "libxslt1-dev")
		}
	}

	// Determine start command
	switch analysis.Framework {
	case "fastapi":
		analysis.StartCommand = fmt.Sprintf("uvicorn %s:app --host 0.0.0.0 --port %d", strings.TrimSuffix(analysis.Entrypoint, ".py"), analysis.Port)
	case "flask":
		analysis.StartCommand = fmt.Sprintf("flask run --host=0.0.0.0 --port=%d", analysis.Port)
	case "django":
		analysis.StartCommand = fmt.Sprintf("python manage.py runserver 0.0.0.0:%d", analysis.Port)
	default:
		analysis.StartCommand = fmt.Sprintf("python %s", analysis.Entrypoint)
	}

	return analysis, nil
}

func (p *Python) fileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

// GenerateDockerfile generates a Dockerfile for Python projects based on analysis
func (p *Python) GenerateDockerfile(codebasePath string) (string, error) {
	// Analyze the Python project
	analysis, err := p.analyzePythonProject(codebasePath)
	if err != nil {
		return "", fmt.Errorf("failed to analyze Python project: %w", err)
	}

	pythonVersion := analysis.PythonVersion
	if pythonVersion == "" {
		pythonVersion = "3.11"
	}

	// Determine dependency management approach
	var copyDeps, installDeps string
	if analysis.UsePoetry {
		copyDeps = `COPY pyproject.toml poetry.lock ./`
		installDeps = `RUN pip install poetry && \
    poetry config virtualenvs.create false && \
    poetry install --only=main`
	} else if analysis.UsePipenv {
		copyDeps = `COPY Pipfile Pipfile.lock ./`
		installDeps = `RUN pip install pipenv && \
    pipenv install --system --deploy`
	} else {
		copyDeps = `COPY requirements.txt ./`
		installDeps = `RUN pip install --no-cache-dir -r requirements.txt`
	}

	// System dependencies
	systemDepsInstall := ""
	if len(analysis.SystemDeps) > 0 {
		systemDepsInstall = fmt.Sprintf(`RUN apt-get update && \
    apt-get install -y %s && \
    rm -rf /var/lib/apt/lists/*`, strings.Join(analysis.SystemDeps, " "))
	}

	dockerfile := fmt.Sprintf(`# Auto-generated Dockerfile for Python application
# Generated by BYOP Engine - Python Stack Analyzer

FROM python:%s-slim

# Set working directory
WORKDIR /app

# Install system dependencies
%s

# Upgrade pip
RUN pip install --upgrade pip

# Copy dependency files
%s

# Install Python dependencies
%s

# Copy source code
COPY . .

# Create non-root user
RUN useradd --create-home --shell /bin/bash app && \
    chown -R app:app /app
USER app

# Expose port
EXPOSE %d

# Start the application
CMD ["%s"]
`,
		pythonVersion,
		systemDepsInstall,
		copyDeps,
		installDeps,
		analysis.Port,
		analysis.StartCommand,
	)

	return dockerfile, nil
}
