'use strict';
// Fabric smart contract classes
const { Contract, Context } = require('fabric-contract-api');

/**
 * Define PharmaLedger smart contract by extending Fabric Contract class
 *
 */
class PharmaLedgerContract extends Contract {

    constructor() {
        // Unique namespace pcn - PharmaChainNetwork when multiple contracts per chaincode file
        super('org.pln.PharmaLedgerContract');
    }
    /**
     * Instantiate to set up ledger.
     * @param {Context} ctx the transaction context
     */

    async initLedger(ctx) {
        console.info('============= START : Initialize Ledger ===========');
       
    }

    async addNewProject(ctx,ID,projectName, clientID, descreption ,deadline,projectStatus,projectLeaderID,estimatedDuration,estimatedBudget,projectProgress) {
        //let ID="ProjectID"+ (new Date()).getTime();
        console.info('============= START : adding Ledger ===========');
        let dt = new Date().toString();

        const leaderAsBytes = await ctx.stub.getState(projectLeaderID); // get the  from chaincode state
        if (!leaderAsBytes || leaderAsBytes.length === 0) {
            throw new Error(`${leaderAsBytes} projectLeader does not exist`);
        }
        
        const cliAsBytes = await ctx.stub.getState(clientID); // get the  from chaincode state
        if (!cliAsBytes || cliAsBytes.length === 0) {
            throw new Error(`${clientID} Client does not exist`);
        }

        const client = JSON.parse(cliAsBytes.toString());

        client.projects.push(ID);

        await ctx.stub.putState(clientID, Buffer.from(JSON.stringify(client)));



        const leader = JSON.parse(leaderAsBytes.toString());

        leader.leader.push(ID);

        await ctx.stub.putState(projectLeaderID, Buffer.from(JSON.stringify(leader)));



        const project = {
            projectID:ID,
            projectName,
            clientID,
            projectLeaderID,
            descreption,
            deadline,
            docType:"project",
            projectStatus,
            estimatedDuration,
            estimatedBudget,
            projectProgress,
            createDateTime: dt,
            lastUpdated: dt,
            tasks:[]
        };




        await ctx.stub.putState(ID, Buffer.from(JSON.stringify(project)));
        

    }

    async editProject(ctx, projectID,projectName, clientID, descreption ,deadline,projectStatus,projectLeaderID,estimatedDuration,estimatedBudget,projectProgress) {
       console.info('============= START : edititing===========');
        let dt = new Date().toString();

        const proAsBytes = await ctx.stub.getState(projectID); // get the  from chaincode state
        if (!proAsBytes || proAsBytes.length === 0) {
            throw new Error(`${projectID} does not exist`);
        }
        


        const pro = JSON.parse(proAsBytes.toString());

        //console.log("before edit"+pro);

        if(pro.clientID!=clientID)
        {
            const cliAsBytes = await ctx.stub.getState(clientID); // get the  from chaincode state
            if (!cliAsBytes || cliAsBytes.length === 0) {
                throw new Error(`${clientID} Client does not exist`);
            }

            const client = JSON.parse(cliAsBytes.toString());

            client.projects.push(projectID);
    

            const cliOldAsBytes = await ctx.stub.getState(pro.clientID);

            const oldClient = JSON.parse(cliOldAsBytes.toString());

            let index = oldClient.projects.indexOf(projectID);
            console.log(oldClient.projects)
            console.log(projectID)

            console.log("index====        "+index)
            
            if (index > -1) {
                oldClient.projects.splice(index, 1);
            }
            else{
                throw new Error(` old client dont hace this project`);

            }

            await ctx.stub.putState(pro.clientID, Buffer.from(JSON.stringify(oldClient)));
            await ctx.stub.putState(clientID, Buffer.from(JSON.stringify(client)));

        }



        if(pro.projectLeaderID!=projectLeaderID)
        {
            const leadAsBytes = await ctx.stub.getState(projectLeaderID); // get the  from chaincode state
            if (!leadAsBytes || leadAsBytes.length === 0) {
                throw new Error(`${projectLeaderID} projectLeader does not exist`);
            }

            const lead = JSON.parse(leadAsBytes.toString());

            lead.leader.push(projectID);
    
            ///////

            const leadOldAsBytes = await ctx.stub.getState(pro.projectLeaderID);

            const oldleader= JSON.parse(leadOldAsBytes.toString());

            let index = oldleader.leader.indexOf(projectID);
            if (index > -1) {
                oldleader.leader.splice(index, 1);
            }
            else{
                throw new Error(` Old Emplyee not aLeader for this project`);
            }
            
            await ctx.stub.putState(pro.projectLeaderID, Buffer.from(JSON.stringify(oldleader)));
            await ctx.stub.putState(projectLeaderID, Buffer.from(JSON.stringify(lead)));

        }

           
           pro.projectName=projectName
           pro.clientID=clientID
           pro.descreption=descreption
           pro.deadline=deadline
           pro.projectStatus=projectStatus
           pro.projectLeaderID=projectLeaderID
           pro.estimatedDuration=estimatedDuration
           pro.estimatedBudget=estimatedBudget
           pro.projectProgress=projectProgress
           pro.lastUpdated= dt
       
        await ctx.stub.putState(projectID, Buffer.from(JSON.stringify(pro)));

    }

    async queryProject(ctx, projectID) {
        const proAsBytes = await ctx.stub.getState(projectID); // get the  from chaincode state
        if (!proAsBytes || proAsBytes.length === 0) {
            throw new Error(`${projectID} does not exist`);
        }
        console.log(proAsBytes.toString());
        return proAsBytes.toString();
    }

    async queryAllProjects(ctx) {
        console.info('=============  queryAllPro ===========');

        const startKey = '';
        const endKey = '';
        const allResults = [];
        for await (const {key, value} of ctx.stub.getStateByRange(startKey, endKey)) {
            const strValue = Buffer.from(value).toString('utf8');
            let record;
            try {
                record = JSON.parse(strValue);
            } catch (err) {
                console.log(err);
                record = strValue;
            }
            if(record.docType=="project")
            allResults.push({ Key: key, Record: record });
        }
        console.info(allResults);
        return JSON.stringify(allResults);
    }

    async changeStatusProject(ctx, projectID, newStatus) {
        console.info('============= START : changestatus ===========');

        const proAsBytes = await ctx.stub.getState(projectID); // get the pro from chaincode state
        if (!proAsBytes || proAsBytes.length === 0) {
            throw new Error(`${projectID} does not exist`);
        }
        const pro = JSON.parse(proAsBytes.toString());
        pro.projectStatus = newStatus;

        await ctx.stub.putState(projectID, Buffer.from(JSON.stringify(pro)));
        console.info('============= END : change status ===========');
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                       task

    async addNewTask(ctx, ID,projectID, taskName, taskdescreption,taskStatus, defecaltDegree,taskEmployeeID,estematedTaskDuration,taskDeadline,taskWage) {
       // let ID="TaskID"+ (new Date()).getTime();

        const emAsBytes = await ctx.stub.getState(taskEmployeeID); // get the  from chaincode state
        if (!emAsBytes || emAsBytes.length === 0) {
            throw new Error(`${taskEmployeeID} Employee does not exist`);
        }

        const emply = JSON.parse(emAsBytes.toString());

        emply.tasks.push(ID);

        await ctx.stub.putState(taskEmployeeID, Buffer.from(JSON.stringify(emply)));
        
        
        let dt = new Date().toString();
        const task ={
            taskId:ID,
            projectID,
            taskName,
            docType:"task",
            taskdescreption,
            taskStatus,
            defecaltDegree,
            estematedTaskDuration,
            taskDeadline,
            createDateTime:dt,
            lastUpdated:dt,
            taskEmployeeID,
            taskWage
        }
        const proAsBytes = await ctx.stub.getState(projectID); // get the project from chaincode state
        if (!proAsBytes || proAsBytes.length === 0) {
            throw new Error(`${projectID} does not exist`);
        }
        
        const pro = JSON.parse(proAsBytes.toString());
        pro.tasks.push(task.taskId);
        
        await ctx.stub.putState(projectID, Buffer.from(JSON.stringify(pro)));
        await ctx.stub.putState(task.taskId, Buffer.from(JSON.stringify(task)));
    }

    async editTask(ctx, taskId, taskName, taskdescreption,taskStatus, defecaltDegree,taskEmployeeID,estematedTaskDuration,taskDeadline,taskWage) {
        //  console.info('============= START : adding Ledger ===========');
          let dt = new Date().toString();
  


          
          const taskAsBytes = await ctx.stub.getState(taskId); 
          if (!taskAsBytes || taskAsBytes.length === 0) {
              throw new Error(`${taskId} does not exist`);
          }

          const ta = JSON.parse(taskAsBytes.toString());   


          if(ta.taskEmployeeID!=taskEmployeeID)
          {
              const emAsBytes = await ctx.stub.getState(taskEmployeeID); // get the  from chaincode state
              if (!emAsBytes || emAsBytes.length === 0) {
                  throw new Error(`${taskEmployeeID} employee does not exist`);
              }
  
              const emp = JSON.parse(emAsBytes.toString());
  
              emp.tasks.push(taskId);
      
  
              const OldAsBytes = await ctx.stub.getState(ta.taskEmployeeID);
  
              const old = JSON.parse(OldAsBytes.toString());
  
              let index = old.tasks.indexOf(taskId);
              if (index > -1) {
                old.tasks.splice(index, 1);
              }
              else
              {
                throw new Error(` Old Emplyee not aLeader for this project`);
              }
              
              await ctx.stub.putState(ta.taskEmployeeID, Buffer.from(JSON.stringify(old)));
              await ctx.stub.putState(taskEmployeeID, Buffer.from(JSON.stringify(emp)));

            }


          ta.taskName=taskName
          ta.taskdescreption=taskdescreption
          ta.taskStatus=taskStatus
          ta.defecaltDegree=defecaltDegree
          ta.taskEmployeeID=taskEmployeeID
          ta.estematedTaskDuration=estematedTaskDuration
          ta.taskDeadline=taskDeadline
          ta.taskWage=taskWage
          ta.lastUpdated=dt
          
          
         
          await ctx.stub.putState(taskId, Buffer.from(JSON.stringify(ta)));
  
      }

    async queryAllTasks(ctx) {
        console.info('=============  queryAlltasks ===========');

        const startKey = '';
        const endKey = '';
        const allResults = [];
        for await (const {key, value} of ctx.stub.getStateByRange(startKey, endKey)) {
            const strValue = Buffer.from(value).toString('utf8');
            let record;
            try {
                record = JSON.parse(strValue);
            } catch (err) {
                console.log(err);
                record = strValue;
            }
            if(record.docType=="task")
            allResults.push({ Key: key, Record: record });
        }
        console.info(allResults);
        return JSON.stringify(allResults);
    }


    async queryAllTasksForAProject(ctx ,projectID ) {

        console.info('=============  queryAlltasksfor A PROJECT ===========');


        const proAsBytes = await ctx.stub.getState(projectID);
        if (!proAsBytes || proAsBytes.length === 0) {
            throw new Error(`${projectID} does not exist`);
        }
        const pro = JSON.parse(proAsBytes.toString());


        const allResults = [];
        console.info(pro.tasks);

        for (let task in pro.tasks) {
            const taskAsBytes = await ctx.stub.getState(pro.tasks[task]);
            console.info(pro.tasks[task]); 
            if (!taskAsBytes || taskAsBytes.length === 0) {
                throw new Error(`${pro.tasks[task]} task does not exist`);
            }
            const STask = Buffer.from(taskAsBytes).toString('utf8');
            let record;
            try {
                record = JSON.parse(STask);
            } catch (err) {
                console.log(err);
                record = STask;
            }
            if(record.docType=="task")
            allResults.push({ Key: pro.tasks[task], Record: record });
        }
        console.info(allResults);
        return JSON.stringify(allResults);
    }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    async addNewEmployee(ctx,ID,firstName,lastName, phoneNumber ,email) {
        
        //let ID="EmployyID"+ (new Date()).getTime();
        let dt = new Date().toString();
        const Employee ={
            employeeId:ID,
            firstName,
            lastName,
            phoneNumber,
            email,
            createDateTime: dt,
            lastUpdated: dt,
            docType:"Employee",
            leader:[],
            tasks:[],
        }
               
        await ctx.stub.putState(ID, Buffer.from(JSON.stringify(Employee)));
     
    }


    async editEmployee(ctx,ID,firstName,lastName, phoneNumber ,email) {
        
        //let ID="ClientID"+  (new Date()).getTime();
        let dt = new Date().toString();
        const emAsBytes = await ctx.stub.getState(ID); 
        if (!emAsBytes || emAsBytes.length === 0) {
            throw new Error(`${ID} does not exist`);
        }

        const emp = JSON.parse(emAsBytes.toString());   

        emp.firstName=firstName;
        emp.lastName=lastName;
        emp.phoneNumber=phoneNumber;
        emp.email=email;
        emp.lastUpdated=dt;
               
        await ctx.stub.putState(ID, Buffer.from(JSON.stringify(emp)));
     
    }

    async queryEmployee(ctx, employeeId) {
        const proAsBytes = await ctx.stub.getState(employeeId);
        if (!proAsBytes || proAsBytes.length === 0) {
            throw new Error(`${employeeId} does not exist`);
        }
        let res=proAsBytes.toString();
        let record = JSON.parse(res);
        console.log(res);
        if(record.docType!="Employee")
        {
            throw new Error(`${employeeId} is a ${record.docType}`);
        }
        return proAsBytes.toString();
    }




    async queryAllEmployee (ctx) {
        const startKey = '';
        const endKey = '';
        const allResults = [];
        for await (const {key, value} of ctx.stub.getStateByRange(startKey, endKey)) {
            const strValue = Buffer.from(value).toString('utf8');
            let record;
            try {
                record = JSON.parse(strValue);
            } catch (err) {
                console.log(err);
                record = strValue;
            }
            if(record.docType=="Employee")
            allResults.push({ Key: key, Record: record });
        }
        console.info(allResults);
        return JSON.stringify(allResults);
    }


    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    async addNewClient(ctx,ID,firstName,lastName, phoneNumber ,email) {
        
        //let ID="ClientID"+  (new Date()).getTime();
        let dt = new Date().toString();
        const Client ={
            clientId:ID,
            firstName,
            lastName,
            phoneNumber,
            email,
            projects:[],
            docType:"Client",
            createDateTime: dt,
            lastUpdated: dt,
        }
               
        await ctx.stub.putState(ID, Buffer.from(JSON.stringify(Client)));
     
    }

    
    async editClient(ctx,ID,firstName,lastName, phoneNumber ,email) {
        
        //let ID="ClientID"+  (new Date()).getTime();
        let dt = new Date().toString();
        const ckiAsBytes = await ctx.stub.getState(ID); 
        if (!ckiAsBytes || ckiAsBytes.length === 0) {
            throw new Error(`${ID} does not exist`);
        }

        const client = JSON.parse(ckiAsBytes.toString());   

        client.firstName=firstName;
        client.lastName=lastName;
        client.phoneNumber=phoneNumber;
        client.email=email;
        client.lastUpdated=dt;
               
        await ctx.stub.putState(ID, Buffer.from(JSON.stringify(client)));
     
    }


    async queryClient(ctx, clientId) {
        const proAsBytes = await ctx.stub.getState(clientId);
        if (!proAsBytes || proAsBytes.length === 0) {
            throw new Error(`${clientId} does not exist`);
        }
        let res=proAsBytes.toString();
        let record = JSON.parse(res);
        console.log(res);
        if(record.docType!="Client")
        {
            throw new Error(`${clientId} is a ${record.docType}`);
        }
        return proAsBytes.toString();
    }



    async queryAllClient (ctx) {
        const startKey = '';
        const endKey = '';
        const allResults = [];
        for await (const {key, value} of ctx.stub.getStateByRange(startKey, endKey)) {
            const strValue = Buffer.from(value).toString('utf8');
            let record;
            try {
                record = JSON.parse(strValue);
            } catch (err) {
                console.log(err);
                record = strValue;
            }
            if(record.docType=="Client")
            allResults.push({ Key: key, Record: record });
        }
        console.info(allResults);
        return JSON.stringify(allResults);
    }

    async callApi(ctx, apiRequest) {
        console.info('======== START : callApiRequest ========');
        console.info(apiRequest);
        // ClientIdentity
        let id = await ctx.clientIdentity.getID();
        let idBytes = await ctx.clientIdentity.getIDBytes();
        let mspid = await ctx.clientIdentity.getMSPID();
        let clientIdentity = 'id: ' + id + ', ' +
        'idBytes: ' + idBytes + ', ' +
        'mspid: ' + mspid + ' '
        ;
        console.info('======== END : callApiRequest ========');
        return '*** ClientIdentity *** ' + clientIdentity;
        }



}
module.exports = PharmaLedgerContract;
