import pandas as pd
from unidecode import unidecode


def keep_columns(
    df: pd.DataFrame, columns_to_keep: list[tuple[str, int]]
) -> pd.DataFrame:
    existing_columns = [col for col, _ in columns_to_keep if col in df.columns]
    df = df[existing_columns].fillna("N/A")

    return df


def process_wos_data(df: pd.DataFrame, header: list[tuple[str, int]]) -> pd.DataFrame:
    for column, new_index in header:
        replaced_column_data = df[column].fillna("N/A")
        df.pop(column)
        df.insert(new_index, column, replaced_column_data)

    df.loc[:, "AU"] = df["AU"].apply(
        lambda x: (
            "; ".join(
                [
                    " ".join(
                        [
                            f"{word[0]}.{word[1:]}"
                            if len(word) == 2 and word.isupper()
                            else word
                            for word in name.split()
                        ]
                    )
                    + "."
                    if "," in name
                    else name
                    for name in x.split(";")
                ]
            )
            if pd.notna(x)
            else x
        )
    )

    df.loc[:, "AU"] = df["AU"].apply(lambda x: x.replace(",", ""))

    return df


def process_scopus_data(
    df: pd.DataFrame, header: list[tuple[str, int]]
) -> pd.DataFrame:
    for column, new_index in header:
        replaced_column_data = df[column].fillna("N/A")
        df.pop(column)
        df.insert(new_index, column, replaced_column_data)

    for column in df.columns:
        if df[column].dtype == "object":
            if column == "Abstract":
                df.loc[:, column] = df[column].apply(
                    lambda x: (
                        x.replace("[No abstract available]", "N/A")
                        if pd.notna(x)
                        else x
                    )
                )

                df.loc[:, column] = df[column].apply(
                    lambda x: (
                        unidecode(x).replace('"', "").lower().strip()
                        if pd.notna(x)
                        else x
                    )
                )

    return df


def merge_and_process(
    df_target: pd.DataFrame, df_visitor: pd.DataFrame, mapping: dict, subset_cols: list
) -> pd.DataFrame:
    visitor_standardized = df_visitor.rename(columns=mapping)
    df = pd.concat([df_target, visitor_standardized], ignore_index=True)
    doi_col = next((c for c in ["DOI", "DI"] if c in df.columns), None)

    if doi_col:
        mask_duplicates = df.duplicated(subset=doi_col)
        mask_na_values = df[doi_col].isna()
        mask_to_keep = ~mask_duplicates | mask_na_values
        df = df[mask_to_keep]

    df = df.drop_duplicates(subset=subset_cols, keep="first")

    return df
