/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   parser.c                                           :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: sede-san <sede-san@student.42madrid.com    +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2025/10/22 18:37:38 by sede-san          #+#    #+#             */
/*   Updated: 2026/02/09 18:50:43 by sede-san         ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "parser.h"

// parse exclusive
static char			*extract_next_command(char *line, size_t *index);
static char			*trim_whitespaces(char *line, size_t *start, size_t *end);
// static void			set_pipes(t_list *commands);

// common
static void			find_boundary(char *line, size_t *index, char bound_char);

// command exclusive
static t_command	*cmdnew(char *line, t_minishell *minishell);
static void			set_argv(t_command *command, char *line, t_minishell *minishell);
static void			expand_envs(char *arg, t_minishell *minishell);
static char			**lst_to_argv(t_list *argv_list);
static void			set_argc(t_command *command);
static void			set_infile(t_command *command);
static void			set_outfile(t_command *command);

t_list	*parse(
	char *line,
	t_minishell *minishell
) {
	t_list		*commands;
	t_command	*command;
	char		*command_str;
	size_t		i;

	if (line == NULL)
		return (NULL);
	commands = NULL;
	i = 0;
	while (line[i] != '\0')
	{
		/* TODO: re-enable when parser consumes lexer tokens */
		/* tokens = tokenize(); */
		command_str = extract_next_command(line, &i);
		if (command_str != NULL)
		{
			command = cmdnew(command_str, minishell);
			free(command_str);
			if (command != NULL)
				ft_lstadd_back(&commands, ft_lstnew(command));
		}
	}
	// set_pipes(commands);
	return (commands);
}

// static void	set_pipes(
// 	t_list *commands
// ) {
// 	t_list		*current_command;
// 	t_list		*previous_command;
// 	t_list		*next_command;
// 	t_command	*command;

// 	previous_command = NULL;
// 	current_command = commands;
// 	while (current_command != NULL)
// 	{
// 		command = (t_command *)current_command->content;
// 		if (previous_command != NULL)
// 			command->piped_from = (t_command *)previous_command->content;
// 		next_command = current_command->next;
// 		if (next_command != NULL)
// 			command->piped_to = (t_command *)next_command->content;
// 		previous_command = current_command;
// 		current_command = current_command->next;
// 	}
// }

static char	*extract_next_command(
	char *line,
	size_t *index
) {
	char	*command_str;
	size_t	start;
	size_t	end;

	start = *index;
	find_boundary(line, index, '|');
	end = *index;
	command_str = trim_whitespaces(line, &start, &end);
	while (line[*index] == '|' || ft_isspace(line[*index]))
		(*index)++;
	return (command_str);
}

static void	find_boundary(
	char *line,
	size_t *index,
	char bound_char
) {
	bool	in_single_quote;
	bool	in_double_quote;

	in_single_quote = false;
	in_double_quote = false;
	while (line[*index] != '\0')
	{
		if (line[*index] == '\'' && !in_double_quote)
			in_single_quote = !in_single_quote;
		else if (line[*index] == '"' && !in_single_quote)
			in_double_quote = !in_double_quote;
		if (line[*index] == bound_char && !in_single_quote && !in_double_quote)
			break ;
		(*index)++;
	}
}

static char	*trim_whitespaces(
	char *line,
	size_t *start,
	size_t *end
) {
	while (*start < *end && ft_isspace(line[*start]))
		(*start)++;
	while (*end > *start && ft_isspace(line[*end - 1]))
		(*end)--;
	if (*end > *start)
		return (ft_substr(line, *start, *end - *start));
	return (NULL);
}

static t_command	*cmdnew(
	char *line,
	t_minishell *minishell
) {
	t_command	*command;

	command = (t_command *)ft_calloc(1, sizeof(t_command));
	if (!command)
		return (NULL);
	// resolve_heredoc
	set_argv(command, line, minishell);
	if (!command->argv)
	{
		free(command);
		return (NULL);
	}
	set_argc(command);
	set_infile(command);
	set_outfile(command);
	return (command);
}

static void	set_argv(
	t_command *command,
	char *line,
	t_minishell *minishell
) {
	t_list	*argv_list;
	char	*arg;
	size_t	i;
	size_t	start;
	size_t	end;

	if (line == NULL)
		return ;
	i = 0;
	argv_list = NULL;
	while (line[i] != '\0')
	{
		start = i;
		find_boundary(line, &i, ' ');
		end = i;
		arg = trim_whitespaces(line, &start, &end);
		expand_envs(arg, minishell);
		if (arg != NULL)
			ft_lstadd_back(&argv_list, ft_lstnew(arg));
		while (ft_isspace(line[i]))
			i++;
	}
	command->argv = lst_to_argv(argv_list);
	ft_lstclear(&argv_list, free);
}

static void	expand_envs(
	char *arg,
	t_minishell *minishell
) {
	// TODO
	(void)arg;
	(void)minishell;
}

static char	**lst_to_argv(
	t_list *argv_list
) {
	char	**argv;
	t_list	*current_arg;
	size_t	i;	

	argv = (char **)ft_calloc(ft_lstsize(argv_list) + 1, sizeof(char *));
	if (!argv)
		return (NULL);
	i = 0;
	current_arg = argv_list;
	while (current_arg != NULL)
	{
		argv[i] = ft_strdup((char *)current_arg->content);
		i++;
		current_arg = current_arg->next;
	}
	return (argv);
}

static void	set_argc(
	t_command *command
) {
	int	argc;

	argc = 0;
	while (command->argv[argc] != NULL)
		argc++;
	command->argc = argc;
}

static void	set_infile(
	t_command *command
) {
	// test_infile
	/* command->infile = -1; */
	(void)command;
}

static void	set_outfile(
	t_command *command
) {
	// test_outfile
	/* command->outfile = STDOUT_FILENO; */
	(void)command;
}
