/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   export.c                                           :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: sede-san <sede-san@student.42madrid.com    +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2026/02/09 22:05:00 by codex             #+#    #+#             */
/*   Updated: 2026/02/14 02:02:14 by sede-san         ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "builtins.h"

static uint8_t	export_one(char *arg, t_minishell *msh);
static uint8_t	print_exported(t_minishell *msh);
static void		**entries_to_array(t_list *lst, size_t *count,
						bool add_oldpwd);
static void		sort_entries(t_map_entry **entries, size_t count);
bool			export_is_valid_identifier(const char *arg, size_t name_len);
void			export_parse_assignment(char *arg, char **eq_pos,
					size_t *name_len, bool *append);
uint8_t			export_set_assigned_value(const char *name, char *eq_pos,
					bool append, t_minishell *msh);
bool			export_print_declaration(const char *name, const char *value);
static t_map_entry	g_oldpwd_entry = {"OLDPWD", NULL};

uint8_t	builtin_export(
	t_command cmd,
	t_minishell *msh
)
{
	uint8_t	status;
	uint8_t	result;
	size_t	i;

	if (cmd.argc == 1)
		return (print_exported(msh));
	status = EXIT_SUCCESS;
	i = 0;
	while (cmd.argv[++i] != NULL)
	{
		result = export_one(cmd.argv[i], msh);
		if (result == 2)
			return (2);
		if (result != EXIT_SUCCESS)
			status = EXIT_FAILURE;
	}
	return (status);
}

static uint8_t	export_one(
	char *arg,
	t_minishell *msh
)
{
	char	*eq_pos;
	char	*name;
	size_t	name_len;
	bool	append;

	if (arg[0] == '-' && arg[1] != '\0')
		return (ft_eprintf("minishell: export: %s: invalid option\n", arg),
			ft_eputendl("export: usage: export [name[=value] ...]"), 2);
	export_parse_assignment(arg, &eq_pos, &name_len, &append);
	if (!export_is_valid_identifier(arg, name_len))
		return (ft_eprintf(
				"minishell: export: `%s': not a valid identifier\n", arg),
			EXIT_FAILURE);
	name = ft_substr(arg, 0, name_len);
	if (name == NULL)
		return (EXIT_FAILURE);
	if (export_set_assigned_value(name, eq_pos, append, msh) != EXIT_SUCCESS)
		return (free(name), EXIT_FAILURE);
	free(name);
	return (EXIT_SUCCESS);
}

static uint8_t	print_exported(
	t_minishell *msh
)
{
	t_list		*entries;
	t_map_entry	**sorted_entries;
	size_t		count;
	size_t		i;
	bool		add_oldpwd;

	entries = ft_hashmap_entries(msh->variables.environment);
	if (entries == NULL)
		return (EXIT_SUCCESS);
	add_oldpwd = !ft_hashmap_contains_key(msh->variables.environment, "OLDPWD");
	sorted_entries = (t_map_entry **)entries_to_array(entries, &count,
			add_oldpwd);
	ft_lstclear_nodes(&entries);
	if (sorted_entries == NULL)
		return (EXIT_FAILURE);
	sort_entries(sorted_entries, count);
	i = 0;
	while (i < count)
	{
		if (!export_print_declaration((char *)sorted_entries[i]->key,
				(char *)sorted_entries[i]->value))
			return (free(sorted_entries), EXIT_FAILURE);
		i++;
	}
	free(sorted_entries);
	return (EXIT_SUCCESS);
}

static void	**entries_to_array(
	t_list *entries,
	size_t *count,
	bool add_oldpwd
)
{
	void	**array;
	t_list	*node;
	t_map_entry	*entry;
	size_t	i;

	*count = (size_t)ft_lstsize(entries) + (size_t)add_oldpwd;
	array = (void **)malloc(sizeof(void *) * (*count));
	if (array == NULL)
		return (NULL);
	i = 0;
	node = entries;
	while (node != NULL)
	{
		entry = (t_map_entry *)node->content;
		if (entry != NULL && ft_strcmp((char *)entry->key, "_") != 0)
			array[i++] = entry;
		node = node->next;
	}
	if (add_oldpwd)
		array[i++] = &g_oldpwd_entry;
	*count = i;
	return (array);
}

static void	sort_entries(
	t_map_entry **entries,
	size_t count
)
{
	size_t		i;
	size_t		j;
	t_map_entry	*tmp;

	i = 0;
	while (i < count)
	{
		j = i + 1;
		while (j < count)
		{
			if (ft_strcmp((char *)entries[i]->key,
					(char *)entries[j]->key) > 0)
			{
				tmp = entries[i];
				entries[i] = entries[j];
				entries[j] = tmp;
			}
			j++;
		}
		i++;
	}
}
