/****
DIAMOND protein sequence aligner
Copyright (C) 2012-2026 Benjamin J. Buchfink

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
****/
// SPDX-License-Identifier: GPL-3.0-or-later

#include "basic/config.h"
#include "util/log_stream.h"
#include "cluster.h"
#include "basic/statistics.h"
#include "run/workflow.h"
#include "data/fasta/fasta_file.h"

using std::endl;
using std::shared_ptr;
using std::for_each;
using std::vector;
using std::tie;
using std::make_shared;
using std::unique_ptr;
using std::runtime_error;
using std::string;

namespace Cluster {

void reassign() {
	config.database.require();
	config.clustering.require();
	init_thresholds();
	*message_stream << "Coverage cutoff: " << (config.mutual_cover.present() ? config.mutual_cover.get_present() : config.member_cover) << '%' << endl;

	TaskTimer timer("Opening the database");
	shared_ptr<SequenceFile> db;
	try {
		db.reset(SequenceFile::auto_create({ config.database }, SequenceFile::Flags::NEED_LETTER_COUNT | SequenceFile::Flags::ACC_TO_OID_MAPPING | SequenceFile::Flags::OID_TO_ACC_MAPPING));
	}
	catch (FormatDetectionError& e) {
		throw runtime_error("Error opening the database: " + string(e.what()));
	}
	config.db_size = db->letters().value();
	timer.finish();
	*message_stream << "#Database sequences: " << db->sequence_count().value() << ", #Letters: " << db->letters().value() << endl;
	//unique_ptr<Util::Tsv::File> out(open_out_tsv());

	timer.go("Reading the input file");
	vector<OId> clustering = read<OId>(config.clustering, *db);

	timer.go("Finding centroids");
	vector<OId> centroids, members;
	tie(centroids, members) = split(clustering);

	timer.go("Creating member database");
	shared_ptr<FastaFile> member_db; // (db->sub_db(members.cbegin(), members.cend()));
	//member_db->set_seqinfo_ptr(0);

	timer.go("Creating centroid database");
	shared_ptr<FastaFile> centroid_db; // (db->sub_db(centroids.cbegin(), centroids.cend()));
	//centroid_db->set_seqinfo_ptr(0);
	timer.finish();

	statistics.reset();
	config.command = Config::blastp;
	config.max_target_seqs_ = 1;
	config.output_format = { "edge" };
	config.self = false;
	if (config.mutual_cover.present())
		config.query_cover = config.subject_cover = config.mutual_cover.get_present();
	else {
		config.query_cover = config.member_cover;
		config.subject_cover = 0;
	}
	config.sensitivity = from_string<Sensitivity>(cluster_steps(config.approx_min_id, false).back());
	//shared_ptr<Mapback> mapback = make_shared<Mapback>(members.size());
	std::unique_ptr<std::vector<BitVector>> target_seed_hits;
	//Search::run(target_seed_hits, centroid_db, member_db, mapback);

	timer.go("Updating clustering");
	//const int64_t n = update_clustering(clustering.begin(), mapback->centroid_id.cbegin(), members.cbegin(), members.cend(), centroids.cbegin());
	timer.finish();
	
	//*message_stream << "Reassigned members: " << n << '/' << members.size() << endl;

	timer.go("Generating output");
	if (flag_any(db->format_flags(), SequenceFile::FormatFlags::TITLES_LAZY))
		db->init_random_access(0, 0, false);
	//output_mem(*out, *db, clustering);

	timer.go("Closing the database");
	db.reset();
}

}