#ifndef MINISHELL_H
#define MINISHELL_H

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <termios.h>
#include <readline/readline.h>
#include <readline/history.h>

#define MS_PROMPT "minishell> "

extern int g_signal;

typedef enum e_tokentype
{
	TOK_WORD,
	TOK_PIPE,
	TOK_REDIR_IN,
	TOK_REDIR_OUT,
	TOK_REDIR_APPEND,
	TOK_HEREDOC
} t_tokentype;

typedef struct s_token
{
	char *text;
	t_tokentype type;
	struct s_token *next;
} t_token;

typedef enum e_redirtype
{
	REDIR_IN,
	REDIR_OUT,
	REDIR_APPEND,
	REDIR_HEREDOC
} t_redirtype;

typedef struct s_redir
{
	t_redirtype type;
	char *target;
	int fd;
	struct s_redir *next;
} t_redir;

typedef struct s_command
{
	char **argv;
	int argc;
	char *path;
	t_redir *redirs;
} t_command;

typedef struct s_pipeline
{
	t_command **cmds;
	size_t count;
} t_pipeline;

typedef struct s_env
{
	char *key;
	char *value;
	struct s_env *next;
} t_env;

typedef struct s_shell
{
	t_env *env;
	int exit_status;
	int last_status;
	int exit_requested;
	int interactive;
} t_shell;

/* core */
void ms_init(t_shell *sh, char **envp);
void ms_loop(t_shell *sh);
void ms_cleanup(t_shell *sh);
void ms_setup_signals(t_shell *sh);
void ms_set_child_signals(void);
void ms_set_heredoc_signals(void);

/* parser */
t_token *lex_line(const char *line, int *error);
void free_tokens(t_token *toks);

t_pipeline *parse_tokens(t_token *toks, int *error);
void free_pipeline(t_pipeline *p);

int expand_pipeline(t_pipeline *p, t_shell *sh);

/* executor */
int execute_pipeline(t_pipeline *p, t_shell *sh);
int prepare_heredocs(t_pipeline *p, t_shell *sh);
int apply_redirections(t_command *cmd, int *saved_stdin, int *saved_stdout);
void restore_redirections(int saved_stdin, int saved_stdout);
char *resolve_path(const char *cmd, t_shell *sh);

/* env */
void env_init(t_shell *sh, char **envp);
void env_clear(t_shell *sh);
char *env_get(t_shell *sh, const char *key);
int env_set(t_shell *sh, const char *key, const char *value);
int env_unset(t_shell *sh, const char *key);
char **env_to_envp(t_shell *sh);
void env_free_envp(char **envp);
void env_print(t_shell *sh);

/* builtins */
int is_builtin(const char *name);
int exec_builtin(t_command *cmd, t_shell *sh);

/* utils */
int ms_is_space(int c);
int ms_is_alpha(int c);
int ms_is_alnum(int c);
int ms_is_digit(int c);
char *ms_strdup(const char *s);
char *ms_strndup(const char *s, size_t n);
char *ms_strjoin(const char *a, const char *b);
char *ms_strjoin3(const char *a, const char *b, const char *c);
char *ms_substr(const char *s, size_t start, size_t len);
char **ms_split(const char *s, char delim);
void ms_free_split(char **sp);
char *ms_itoa(int n);

#endif
