#pragma once

#include <iostream>
#include <time.h>
//#include <sys/time.h>
#include <thread>
#include <chrono>
#include <functional>
#include <unordered_map>
#include <mutex>
#include "geo_hash.h"
#include <sstream>
#include "car.h"
#include <map>
#include "zlist.h"


#include "confstruct.h"
NAMESPACE_POINT_BEGIN(NAMESPACE_POINT)
//extern ConfStruct g_cs;

struct MyHash
{
    typedef uint64_t result_type;
    result_type operator ()(std::pair<std::string,std::string> p) const
    {
		std::hash<std::string> hs;
        result_type st1 = hs(p.first);
        result_type st2 = hs(p.second);
        return st1^(st2);
    }
};


struct Data
{
    Data(uint64_t ct)
    {
        m_index = 0;
        m_ct.fill(0);
        m_totaldistance = 0;
		m_timestamp = ct;
		m_flag = false;
    }
    void reset()
    {
        m_index = 0;
        m_ct.fill(0);
        m_totaldistance = 0;
		//m_timestamp = time(NULL);
		m_flag = false;
    }
    void increase(const int index)
    {
        m_ct[index]++;
    }
    uint32_t m_index;
    std::array<uint16_t,2> m_ct;
    double   m_totaldistance;
	uint64_t m_timestamp;
	bool m_flag;
};

struct TcardInterface
{
   // TcardInterface()=default;
    TcardInterface(std::pair<std::string,std::string> sp,uint64_t ct,uint64_t owner,int size)
        :m_cardid(sp)
        ,m_timestamp(ct)
		,m_owner(owner)
		,SIZE(size)
    {}
    //tsp timestamp
	std::tuple<bool,std::string> setindex(uint64_t tsp,const std::string &cardid,const double d=0,bool ctflag =false)
	{
		bool flag = false;
		assert(m_timestamp != 0||tsp != 0);
		std::tuple<bool,std::string> stp(flag,std::string(""));
		//get ct index..first === 0  second == 1
		int arrindex = getstrindex(cardid);

		if(arrindex == -1)
			return stp;
		if (empty())
			grow(tsp);
		//uint64_t tmp_tsp_min = m_timestamp + ((empty()?1:size())-1)*ConfStruct::getCs().split_win_minsec;
		//uint64_t tmp_tsp_max = m_timestamp + (empty()?1:size())*ConfStruct::getCs().split_win_minsec;
		uint64_t tmp_tsp_min = back(0).m_timestamp;
		uint64_t tmp_tsp_max = back(0).m_timestamp + ConfStruct::getCs().split_win_minsec;
		//assert(tsp >= tmp_tsp_min);
		
		do
		{
			if(tsp>=tmp_tsp_min && tsp < tmp_tsp_max)
			{
				//if(empty()) 
					//grow();
				if(!ctflag)
				{
					back(0).m_index++;
					back(0).m_totaldistance+=d;
				}
				else
					back(0).increase(arrindex);
				break;
			}
			else
			{
				if(timeout())
				{
					auto tp = get();
					//查看是否可以告警
					stp = check(std::get<0>(tp),std::get<1>(tp));
					skip(1);
				}
				grow(tsp);
				tmp_tsp_min = back(0).m_timestamp;
				tmp_tsp_max = back(0).m_timestamp + ConfStruct::getCs().split_win_minsec;
			}

		}while(1);
		return stp;
	}

	std::tuple<bool,std::string> checkLast()
	{
		std::tuple<bool,std::string> stp(false,std::string(""));
		if (!timeout() && size()>=ConfStruct::getCs().remote_slot)
		{
			auto tp = get();
			//查看是否可以告警
			stp = check(std::get<0>(tp),std::get<1>(tp));
		}
		return stp;
	}
	void skip(int count)
	{
		for(int i =0;i<count&&i<size();i++)
			m_arr.pop_front();
	}
	bool empty()
	{
		return m_arr.empty();
	}
	int size() 
	{
		return m_arr.size();
	}
	void  grow(uint64_t ct)
	{
		Data d(ct);
		d.reset();
		m_arr.push_back(d);
	}
	Data &back(int index)
	{
		assert(index<(int)size() && index >= 0);
		return m_arr.at(size()-index-1);
	}
	std::tuple<int,int,double> get()
	{
		int total_ix=0,total_ct=0;
		double dis = 0;
		std::for_each(m_arr.begin(),m_arr.end(),[&total_ix,&total_ct,&dis](const Data &d){total_ix += d.m_index;total_ct+=(d.m_ct[0]+d.m_ct[1]);dis+=d.m_totaldistance;});
		return std::make_tuple(total_ix,total_ct,dis);
	}
	bool timeout()
	{
		return size() == SIZE-1;
	}
	std::string getInfo_1()
	{
		std::stringstream ss;
		ss<<m_cardid.first<<"&"<<m_cardid.second<<","<<m_arr[0].m_timestamp/1000<<","<<(back(0).m_timestamp+ConfStruct::getCs().split_win_minsec)/1000 <<",";
		std::for_each(m_arr.begin(),m_arr.end(),[&ss](Data& d){
			if (!d.m_flag)
			{
				ss<<d.m_timestamp/1000<<"&"<<d.m_totaldistance<<"&"<<d.m_index<<",";
				d.m_flag = true;
			}
			
		});
		return ss.str();
	}
	std::string getInfo()
	{
		auto tp = get();
		std::stringstream ss;
		ss<<"{T:"<<std::get<0>(tp)<<","<<std::get<1>(tp)<<","<<std::get<2>(tp)<<"}";
		//ss<<"{Total index:"<<std::get<0>(tp)<<","<<std::get<1>(tp)<<"},";
		//m_arr.for_each([&ss](const Data&x){
		//	ss<<"["<<x.m_index<<","<<x.m_ct[0]+x.m_ct[1]<<"]";
		//});
		return std::move(ss.str());
	}
	inline std::tuple<bool,std::string> check(int index,int ct)
	{
		if(index*1.0/ct>=0.72)
		{
			std::string s = getInfo_1();
			return std::make_tuple(true,s);
		}
		return std::make_tuple(false,std::string(""));
	}
    inline int getstrindex(const std::string cardid)
    {
        if(m_cardid.first == cardid)
          return 0;
        else
          return 1;
        return -1;
    }
public:
    std::pair<std::string,std::string> m_cardid;
    uint64_t m_timestamp;
	uint64_t m_owner;
	std::deque<Data> m_arr;
	int SIZE;
    virtual ~TcardInterface(){} 
};

struct CardFactory
{
    typedef std::vector<std::string>::iterator iter;
    typedef std::map<std::string,std::shared_ptr<card_interface>>  Mapdef;

	void erase(std::pair<std::string,std::string> p,base_card_list &m)
	{   
		{   
			auto it = m[p.first];
			if(it != nullptr)
			{   
				std::shared_ptr<card_interface> bc = it->m_card;
				bc->m_v.erase(std::remove(bc->m_v.begin(),bc->m_v.end(),p.second),bc->m_v.end());
			}   
		}   
		auto it = m[p.second];
		if(it != nullptr)
		{   
			std::shared_ptr<card_interface> bc = it->m_card;
			bc->m_v.erase(std::remove(bc->m_v.begin(),bc->m_v.end(),p.first),bc->m_v.end());
		}   

	}   
	void erase(const uint64_t s,base_card_list &m) 
	{   
		std::lock_guard<std::mutex> lck(m_mtx);
		auto iter = m_map.find(s);
		if(iter != m_map.end())
		{   
			std::pair<std::string,std::string> p = iter->second->m_cardid;
			erase(p,m);
			m_map.erase(iter);
		}   
	}   
	std::map<uint64_t,std::string> erase(const std::shared_ptr<card_interface>&bc,base_card_list &m,std::vector<std::string>&v) 
	{   
		std::map<uint64_t,std::string> tmpvec;
		std::string s =bc->cardId();
		MyHash mh; 
		for(const auto str: v)
		{   
			std::lock_guard<std::mutex> lck(m_mtx);
			uint64_t t = mh(std::make_pair(str,s));
			auto iter = m_map.find(t);
			if(iter != m_map.end())
			{   
				auto bs = checkLast(iter->second);
				if (std::get<0>(bs))
				{
					tmpvec.insert(std::make_pair(t,std::get<1>(bs)));
				}
				std::pair<std::string,std::string> p = iter->second->m_cardid;
				erase(p,m);
				m_map.erase(iter);
			}
		}
		return std::move(tmpvec);
	}


	std::map<uint64_t,std::string> setCT(std::shared_ptr<card_interface>&bc)
	{
		std::map<uint64_t,std::string> tmpvec;
		std::string str = bc->cardId();
		uint64_t cttime = bc->CtTime();
		std::shared_ptr<TcardInterface> ptr = nullptr;

		std::vector<std::string> vec = bc->m_v;
		MyHash mh;
		for(auto it = vec.begin();it != vec.end();it ++)
		{
			uint64_t s = mh(std::make_pair(*it,str));
			std::lock_guard<std::mutex> lck(m_mtx);
			auto iter = m_map.find(s);
			if(iter != m_map.end())
			{
				ptr = iter->second;
				auto sp = ptr->setindex(cttime,str,0,true);
				if (std::get<0>(sp))
				{
					tmpvec.insert(std::make_pair(s,std::get<1>(sp)));
				}

			}
		}
		return std::move(tmpvec);
	}


	std::map<uint64_t,std::string> handlecard(const std::vector<std::string>&& vec,std::shared_ptr<card_interface>&bc, base_card_list &m)
	{
		std::map<uint64_t,std::string> tempvec;
		std::string str =bc->cardId();
		uint64_t cttime = bc->CtTime();
		int x = bc->getX();
		int y = bc->getY();
		std::shared_ptr<TcardInterface> ptr = nullptr;
		MyHash mh;
		double dis = 0;
		for(auto it = vec.begin();it != vec.end();it ++)
		{
			uint64_t s = mh(std::make_pair(*it,str));
			auto iter = m_map.find(s);
			if(iter != m_map.end())
			{
				ptr = iter->second;
			}
			else
			{
				ptr = getPtr(*it,str,cttime,s);
				std::lock_guard<std::mutex> lck(m_mtx);
				m_map.insert(std::make_pair(s,ptr));
				backup(bc,*it,m);
			}
			//do card message.. 
			if(ptr == nullptr)
				continue;
			//dis
			auto cd = m[*it];
			if (cd !=nullptr)
			{
				int x1 = cd->m_card->getX();
				int y1 = cd->m_card->getY();
				dis = sqrt(pow(x-x1,2)+pow(y-y1,2));
			}
			auto sp = ptr->setindex(cttime,str,dis);
			if (std::get<0>(sp))
			{
				tempvec.insert(std::make_pair(s,std::get<1>(sp)));
			}

		}
		return std::move(tempvec);
	}
    inline std::string InfoMessage()
    {
		std::stringstream ss;
		ss<<"S: "<<m_map.size();
		for(auto it : m_map)
		{
			//ss<< " hash info["<<it.first <<"]first cardid:["<<it.second->m_cardid.first<<"]second cardid:["<<it.second->m_cardid.second<<"]Info:{total_size:"<<it.second->size()<<","<<it.second->getInfo()<<"}";
			ss<< "["<<it.second->m_cardid.first<<"]["<<it.second->m_cardid.second<<"]{s:"<<it.second->size()<<","<<it.second->getInfo()<<"}";
		}
		return std::move(ss.str());

    }
    virtual std::map<uint64_t,std::string> selectcard(const iter ib,const iter ie,std::shared_ptr<card_interface>& c,base_card_list & m) = 0;
    virtual std::shared_ptr<TcardInterface> getPtr(const std::string str1,const std::string &str2,const uint64_t ctime,uint64_t) = 0;
    virtual void backup (std::shared_ptr<card_interface>&bc,const std::string str, base_card_list &m)= 0; 
    virtual std::tuple<bool,std::string> checkLast(std::shared_ptr<TcardInterface> &ti)=0;
	virtual ~CardFactory(){}
public:
    std::unordered_map<uint64_t,std::shared_ptr<TcardInterface>>     m_map;
    std::mutex m_mtx;
};
struct CloserCardFactory : CardFactory
{
	/*
	 * 选卡，选出不满足如下条件的卡：
	 * a.
	*/
	std::map<uint64_t,std::string> selectcard(const iter ib,const iter ie,std::shared_ptr<card_interface>& bc, base_card_list &m)
	{
		std::vector<std::string> rc(ib,ie);
		rc.erase(std::remove_if(rc.begin(),rc.end(),[&](const std::string &s){
			if(!(*bc)[s])
				return true;
			auto it = m[s];
			if(it==nullptr)
				return true;
			if(bc->cardId() == s)
				return true;
			uint64_t ct1 = it->m_card->CtTime();
			uint64_t ct2 = bc->CtTime();
			uint64_t ct3 = ct1>ct2?ct1-ct2:ct2-ct1;
			return ct3 > ConfStruct::getCs().limit_sec*1000; 
		}),rc.end());

		auto vec = handlecard(std::move(rc),bc,m);
		return std::move(vec);
	}
    void backup (std::shared_ptr<card_interface>&bc,const std::string str, base_card_list &m)
    {
        bc->m_v.push_back(str);
		std::string s = bc->cardId();
		auto it = m[str];
		if (it != nullptr)
			it->m_card->m_v.push_back(s);
    }
    std::shared_ptr<TcardInterface> getPtr(const std::string str1,const std::string &str2,const uint64_t ctime,uint64_t owner)
    {
        return std::make_shared<TcardInterface>(std::make_pair(str1,str2),ctime,owner,ConfStruct::getCs().closer_slot);
    }
	std::tuple<bool,std::string> checkLast(std::shared_ptr<TcardInterface> &ti)
	{
		return ti->checkLast();
	}
};

struct RemoteCardFactory : CardFactory
{
	std::map<uint64_t,std::string> selectcard(const iter ib,const iter ie,std::shared_ptr<card_interface>& bc, base_card_list &m)
	{
		std::sort(bc->m_v.begin(),bc->m_v.end());
		std::sort(ib,ie);
		std::vector<std::string> v(ie-ib+bc->m_v.size());

		auto it = std::set_difference(bc->m_v.begin(),bc->m_v.end(),ib,ie,v.begin());
		v.resize(it-v.begin());

		v.erase(std::remove_if(v.begin(),v.end(),[&](std::string& s){
			auto it = m[s];
			if(it == nullptr)
				return true;
			uint64_t ct1 = it->m_card->CtTime();
			uint64_t ct2 = bc->CtTime();
			uint64_t ct3 = ct1>ct2?ct1-ct2:ct2-ct1;
			return ct3 > ConfStruct::getCs().limit_sec*1000; 
		}),v.end());

		auto vec = handlecard(std::move(v),bc,m);
		return std::move(vec);
	}
    void backup (std::shared_ptr<card_interface>&bc,const std::string str, base_card_list &m){}
    std::shared_ptr<TcardInterface> getPtr(const std::string str1,const std::string &str2,const uint64_t ctime,uint64_t owner)
    {
        return std::make_shared<TcardInterface>(std::make_pair(str1,str2),ctime,owner,ConfStruct::getCs().remote_slot);
    }
	std::tuple<bool,std::string> checkLast(std::shared_ptr<TcardInterface> &ti)
	{
		return std::make_tuple(false,std::string(""));
	}
};
NAMESPACE_POINT_END(NAMESPACE_POINT)
