package connection

import (
	"io/fs"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/steveyegge/gastown/internal/tmux"
)

// LocalConnection implements Connection for local file and command operations.
type LocalConnection struct {
	tmux *tmux.Tmux
}

// NewLocalConnection creates a new local connection.
func NewLocalConnection() *LocalConnection {
	return &LocalConnection{
		tmux: tmux.NewTmux(),
	}
}

// Name returns "local" for local connections.
func (c *LocalConnection) Name() string {
	return "local"
}

// IsLocal returns true for local connections.
func (c *LocalConnection) IsLocal() bool {
	return true
}

// ReadFile reads the named file.
func (c *LocalConnection) ReadFile(path string) ([]byte, error) {
	data, err := os.ReadFile(path) //nolint:gosec // G304: path is from Connection interface, validated by caller
	if err != nil {
		if os.IsNotExist(err) {
			return nil, &NotFoundError{Path: path}
		}
		if os.IsPermission(err) {
			return nil, &PermissionError{Path: path, Op: "read"}
		}
		return nil, err
	}
	return data, nil
}

// WriteFile writes data to the named file.
func (c *LocalConnection) WriteFile(path string, data []byte, perm fs.FileMode) error {
	err := os.WriteFile(path, data, perm)
	if err != nil {
		if os.IsPermission(err) {
			return &PermissionError{Path: path, Op: "write"}
		}
		return err
	}
	return nil
}

// MkdirAll creates a directory and all parent directories.
func (c *LocalConnection) MkdirAll(path string, perm fs.FileMode) error {
	err := os.MkdirAll(path, perm)
	if err != nil {
		if os.IsPermission(err) {
			return &PermissionError{Path: path, Op: "mkdir"}
		}
		return err
	}
	return nil
}

// Remove removes the named file or empty directory.
func (c *LocalConnection) Remove(path string) error {
	err := os.Remove(path)
	if err != nil {
		if os.IsNotExist(err) {
			return nil // Already gone
		}
		if os.IsPermission(err) {
			return &PermissionError{Path: path, Op: "remove"}
		}
		return err
	}
	return nil
}

// RemoveAll removes the named file or directory and any children.
func (c *LocalConnection) RemoveAll(path string) error {
	err := os.RemoveAll(path)
	if err != nil {
		if os.IsPermission(err) {
			return &PermissionError{Path: path, Op: "remove"}
		}
		return err
	}
	return nil
}

// Stat returns file info for the named file.
func (c *LocalConnection) Stat(path string) (FileInfo, error) {
	fi, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, &NotFoundError{Path: path}
		}
		if os.IsPermission(err) {
			return nil, &PermissionError{Path: path, Op: "stat"}
		}
		return nil, err
	}
	return FromOSFileInfo(fi), nil
}

// Glob returns the names of all files matching the pattern.
func (c *LocalConnection) Glob(pattern string) ([]string, error) {
	matches, err := filepath.Glob(pattern)
	if err != nil {
		return nil, err
	}
	return matches, nil
}

// Exists returns true if the path exists.
func (c *LocalConnection) Exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err
	}
	return true, nil
}

// Exec runs a command and returns its combined output.
func (c *LocalConnection) Exec(cmd string, args ...string) ([]byte, error) {
	return exec.Command(cmd, args...).CombinedOutput()
}

// ExecDir runs a command in the specified directory.
func (c *LocalConnection) ExecDir(dir, cmd string, args ...string) ([]byte, error) {
	command := exec.Command(cmd, args...)
	command.Dir = dir
	return command.CombinedOutput()
}

// ExecEnv runs a command with additional environment variables.
func (c *LocalConnection) ExecEnv(env map[string]string, cmd string, args ...string) ([]byte, error) {
	command := exec.Command(cmd, args...)
	command.Env = os.Environ()
	for k, v := range env {
		command.Env = append(command.Env, k+"="+v)
	}
	return command.CombinedOutput()
}

// TmuxNewSession creates a new tmux session.
func (c *LocalConnection) TmuxNewSession(name, dir string) error {
	return c.tmux.NewSession(name, dir)
}

// TmuxKillSession terminates a tmux session.
func (c *LocalConnection) TmuxKillSession(name string) error {
	return c.tmux.KillSession(name)
}

// TmuxSendKeys sends keys to a tmux session.
func (c *LocalConnection) TmuxSendKeys(session, keys string) error {
	return c.tmux.SendKeys(session, keys)
}

// TmuxCapturePane captures the last N lines from a tmux pane.
func (c *LocalConnection) TmuxCapturePane(session string, lines int) (string, error) {
	return c.tmux.CapturePane(session, lines)
}

// TmuxHasSession returns true if the session exists.
func (c *LocalConnection) TmuxHasSession(name string) (bool, error) {
	return c.tmux.HasSession(name)
}

// TmuxListSessions returns all tmux session names.
func (c *LocalConnection) TmuxListSessions() ([]string, error) {
	return c.tmux.ListSessions()
}

// Verify LocalConnection implements Connection.
var _ Connection = (*LocalConnection)(nil)
