package ru.nbch.indicsearchservice.loader;

import java.io.IOException;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.ibatis.cursor.Cursor;
import org.springframework.stereotype.Component;
import ru.nbch.indicsearchservice.loader.subtable.AccountSubTableLoader;
import ru.nbch.indicsearchservice.model.TableMetaData;
import ru.nbch.indicsearchservice.model.enums.DataType;
import ru.nbch.indicsearchservice.model.enums.SearchParameter;
import ru.nbch.indicsearchservice.util.IndicSearchUtils;
import ru.nbch.indicsearchservice.util.MapperHolder;

@Component
public class AccountTableLoader implements FirstLevelTableLoader, TableLoaderForId {
    private final MapperHolder mapperHolder;
    private final IndicSearchUtils indicSearchUtils;
    private final List<AccountSubTableLoader> accountSubTableLoaders;

    public AccountTableLoader(MapperHolder mapperHolder,
                              IndicSearchUtils indicSearchUtils,
                              List<AccountSubTableLoader> accountSubTableLoaders) {
        this.mapperHolder = mapperHolder;
        this.indicSearchUtils = indicSearchUtils;
        this.accountSubTableLoaders = accountSubTableLoaders;
    }

    @Override
    public String getTableName() {
        return "ACCOUNT";
    }

    @Override
    public Set<String> getTableNamesIfSuitable(DataType dataType, SearchParameter searchParameter) {
        if (dataType == DataType.TUTDF &&
            (searchParameter == SearchParameter.UUID ||
                searchParameter == SearchParameter.ACCT_NUM ||
                searchParameter == SearchParameter.SERIAL_NUM_ACCT ||
                searchParameter == SearchParameter.FID ||
                searchParameter == SearchParameter.PASSPORT ||
                searchParameter == SearchParameter.OGRN)) {
            Set<String> result = new HashSet<>();

            result.add(getTableName());
            result.addAll(accountSubTableLoaders.stream().map(TableLoader::getTableName).toList());

            return result;
        }

        return Set.of();
    }

    @Override
    public void searchBy(UUID taskId,
                         DataType dataType,
                         SearchParameter searchParameter,
                         String searchValue,
                         String memberCode,
                         Map<String, Path> tableFileMap,
                         Map<String, TableMetaData> tableMetaDataMap) {
        if (dataType == DataType.TUTDF) {
            if (searchParameter == SearchParameter.UUID || searchParameter == SearchParameter.ACCT_NUM || searchParameter == SearchParameter.SERIAL_NUM_ACCT) {
                try (Cursor<LinkedHashMap<String, Object>> cursor = mapperHolder.getIndicMapper().findAllByMemberCodeFromAccount(memberCode)) {
                    Set<Integer> foundFids = new HashSet<>();
                    tableFileMap.put(getTableName(), indicSearchUtils.writeRowsToFile(taskId, getTableName(), cursor, foundFids, tableMetaDataMap));
                    accountSubTableLoaders.parallelStream().forEach(tl -> tl.searchByAccountFid(taskId, foundFids, tableFileMap, tableMetaDataMap));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            } else if (searchParameter == SearchParameter.FID) {
                Set<Integer> fids = Set.of(Integer.parseInt(searchValue));

                try (Cursor<LinkedHashMap<String, Object>> cursor = mapperHolder.getIndicMapper().findAllByFidsFromAccount(fids)) {
                    tableFileMap.put(getTableName(), indicSearchUtils.writeRowsToFile(taskId, getTableName(), cursor, tableMetaDataMap));
                    accountSubTableLoaders.parallelStream().forEach(tl -> tl.searchByAccountFid(taskId, fids, tableFileMap, tableMetaDataMap));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    @Override
    public void searchById(UUID taskId,
                           DataType dataType,
                           SearchParameter searchParameter,
                           Set<Integer> fids,
                           String memberCode,
                           Map<String, Path> tableFileMap,
                           Map<String, TableMetaData> tableMetaDataMap) {
        if (dataType == DataType.TUTDF) {
            if (searchParameter == SearchParameter.PASSPORT || searchParameter == SearchParameter.OGRN) {
                try (Cursor<LinkedHashMap<String, Object>> cursor = mapperHolder.getIndicMapper().findAllByFidsFromAccount(fids)) {
                    tableFileMap.put(getTableName(), indicSearchUtils.writeRowsToFile(taskId, getTableName(), cursor, tableMetaDataMap));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
