import { Catch, Injectable } from "@nestjs/common";
import { DataSource } from "typeorm";
import { User } from "./entities/sign_up.entity";
import * as jwt from "jsonwebtoken";
import * as crypto from "crypto";
import { CryptoService } from "src/qr-encrpyt/qr-encrpyt.service";

@Injectable()
export class SignUpService {
  constructor(
    private readonly connection: DataSource,
    private readonly EncryptedService: CryptoService
  ) {}

  async check_old_or_new(userEntity: any) {
    try {
      const decrypt = await this.EncryptedService.decrypt(userEntity.body);
      const decryptedData = JSON.parse(decrypt);
      const [check_in_users] = await this.connection.query(
        "SELECT id, username, has_mpin FROM users WHERE username = ?",
        [decryptedData.username]
      );
      const mobileno = decryptedData.username.slice(2);
      const [check_in_patiant] = await this.connection.query(
        "SELECT id FROM patients WHERE mobileno = ?",
        [mobileno]
      );
  
      let response;
      if (check_in_users) {
        response = [
          {
            userType: "old",
            user_id: check_in_users.id,
            isMPINCreated: true,
          },
        ];
      }
      if (!check_in_users && check_in_patiant) {
        response = [
          {
            userType: "old",
            user_id: null,
            isMPINCreated: false,
          },
        ];
      } else if (!check_in_users) {
        response = [
          {
            userType: "new",
            isMPINCreated: false,
          },
        ];
      }
      const encryptedData = await this.userEncryptRes(response);
      return encryptedData;
    } catch (error) {
      const error_req = {
        status: "failed",
        statusCode: 400,
        message: "Encryption failed",
      };
      const encryptedData = await this.userEncryptRes(error_req);
      return encryptedData;
    }
  }

  async userEncryptRes(res: any) {
    return await this.EncryptedService.encrypt(
      JSON.stringify(res),
      process.env.encryption_key,
      process.env.encryption_iv
    );
  }

  async getDetails(userEntity: User) {
    const [check_in_users] = await this.connection.query(
      "select id user_id,username,user_id profile_id from users where users.username = ?",
      [userEntity.username]
    );
    if (check_in_users) {
      return [
        {
          status: "success",
          message: "user details fetched successfully",
          details: check_in_users,
        },
      ];
    } else {
      return [
        {
          status: "failed",
          message: " failed to fetch user details",
        },
      ];
    }
  }

  async verifyOld(userEntity: User) {
    let encrypted;
    try {
      const key = Buffer.from(process.env.encryption_key, "base64");
      const iv = Buffer.from(process.env.encryption_iv, "base64");

      if (key.length !== 32) throw new Error("Key must be 32 bytes");
      if (iv.length !== 16) throw new Error("IV must be 16 bytes");

      const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
      let decrypted = decipher.update(
        Buffer.from(userEntity.password, "base64")
      );
      decrypted = Buffer.concat([decrypted, decipher.final()]);
      encrypted = decrypted.toString("utf8").trim();
      encrypted = parseInt(encrypted);
    } catch (error) {
      encrypted = userEntity.password;
    }
    console.log(encrypted, "encryptedencrypted");

    const [check_password] = await this.connection.query(
      "select id,user_id from users where users.username = ? and (users.password = ? or users.password = ?)",
      [userEntity.username, userEntity.password, encrypted]
    );
    console.log(check_password, "check_password");

    if (check_password) {
      const JWTexpiresIn = process.env.JWT_EXPIRATION;
      const accessTokenPayload = {
        id: check_password.id,
        JWTexpiresIn: JWTexpiresIn,
      };
      const accessToken = jwt.sign(accessTokenPayload, process.env.JWT_SECRET, {
        expiresIn: JWTexpiresIn,
      });
      await this.connection.query(
        `insert into phr_jwt_token (user_id,token,expiry) values (?,?,DATE_ADD(NOW(), INTERVAL 7 DAY))`,
        [check_password.id, accessToken]
      );

      let aa;
      if (userEntity.username.length > 10) {
        aa = userEntity.username.slice(2);
      } else {
        aa = userEntity.username;
      }
      const getProfile = await this.connection.query(
        `select id from patients where mobileno = ?`,
        [aa]
      );
      console.log(getProfile, "getProfile");
      await this.connection.query(`update users set user_id = ? where id = ?`, [
        getProfile[0].id,
        check_password.id,
      ]);
      if (!check_password.user_id) {
        if (getProfile.length > 0) {
          await this.connection.query(
            `update users set user_id = ? where id = ?`,
            [getProfile[0].id, check_password.id]
          );
          console.log(getProfile, "getProfile");

          return [
            {
              messege: "password verified successfully",
              patient_id: check_password.user_id,
              patient_id_list: getProfile,
              user_details: await this.connection.query(
                "select username,password,id as user_id from users where id = ?",
                [check_password.id]
              ),
              accessToken: accessToken,
            },
          ];
        } else {
          return [
            {
              messege: "password verified successfully",
              patient_id_list: getProfile,
              user_details: await this.connection.query(
                "select username,password,id as user_id from users where id = ?",
                [check_password.id]
              ),
              profileUpdate: "update your profile",
              accessToken: accessToken,
            },
          ];
        }
      }
      return [
        {
          messege: "password verified successfully",
          patient_id_list: getProfile,
          patient_id: check_password.user_id,
          user_details: await this.connection.query(
            "select username,password,id as user_id from users where id = ?",
            [check_password.id]
          ),
          accessToken: accessToken,
        },
      ];
    } else {
      return [
        {
          status: "failed",
          messege: "password verified failed enter correct password",
        },
      ];
    }
  }

  async createnew(userEntity: User) {
    try {
      const [check_in_users] = await this.connection.query(
        `select id from users where users.username = ?`,
        [userEntity.username]
      );
      if (check_in_users) {
        const updatePassword = await this.updatePassword(
          check_in_users.id,
          userEntity
        );
      }

      let encrypted;
      try {
        const key = Buffer.from(process.env.encryption_key, "base64");
        const iv = Buffer.from(process.env.encryption_iv, "base64");
        if (key.length !== 32) throw new Error("Key must be 32 bytes");
        if (iv.length !== 16) throw new Error("IV must be 16 bytes");
        const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
        let decrypted = decipher.update(
          Buffer.from(userEntity.password, "base64")
        );
        decrypted = Buffer.concat([decrypted, decipher.final()]);
        encrypted = decrypted.toString("utf8").trim();
        encrypted = parseInt(encrypted);
      } catch (error) {
        encrypted = userEntity.password;
      }
      userEntity.password = await encrypted;
      let user = null;
      if (check_in_users) {
       await this.connection.query(
              `UPDATE users 
              SET username = ?, password = ?, role = ?, has_mpin = 1 
              WHERE id = ?`,
              [userEntity.username, userEntity.password, "patient", check_in_users.id]
      );
       user = { insertId: check_in_users.id };
      } else {
        const result = await this.connection.query(
          `insert into users (username,password,role,has_mpin) values (?, ?, ?,1)`,
          [userEntity.username, userEntity.password, "patient"]
        );
        user = { insertId: result.insertId }
      }

      const JWTexpiresIn = process.env.JWT_EXPIRATION;
      const accessTokenPayload = {
        id: user.insertId,
        JWTexpiresIn: JWTexpiresIn,
      };
      const accessToken = jwt.sign(accessTokenPayload, process.env.JWT_SECRET, {
        expiresIn: JWTexpiresIn,
      });
      await this.connection.query(
        `insert into phr_jwt_token (user_id,token,expiry) values (?,?,DATE_ADD(NOW(), INTERVAL 7 DAY))`,
        [user.insertId, accessToken]
      );

      let aa;
      if (userEntity.username.length > 10) {
        aa = userEntity.username.slice(2);
      } else {
        aa = userEntity.username;
      }

      const [getProfile] = await this.connection.query(
        `select id from patients where mobileno = ?`,
        [aa]
      );

      if (getProfile) {
        await this.connection.query(
          `update users set user_id = ? where id = ?`,
          [getProfile.id, user.insertId]
        );
        return [
          {
            messege: "password verified successfully",
            patient_id: getProfile.id,
            user_details: await this.connection.query(
              "select username,password,id as user_id from users where id = ?",
              [user.insertId]
            ),
            accessToken: accessToken,
          },
        ];
      } else {
        return [
          {
            messege: "data saved successfully",
            user_details: await this.connection.query(
              "select username,password,id as user_id from users where id = ?",
              [user.insertId]
            ),
            accessToken: accessToken,
          },
        ];
      }
    } catch (error) {
      return error;
    }
  }

  async findsettings(id: number) {
    const userSettings = await this.connection.query(
      `select users.notification_enabled,languages.language,users.has_mpin from
      users join languages on languages.id = users.lang_id
        where users.id = ?`,
      [id]
    );
    return userSettings;
  }

  async updatePassword(id: number, userEntity: User) {
    let encrypted;
    try {
      console.log(userEntity, "userEntity");

      const key = Buffer.from(process.env.encryption_key, "base64");
      const iv = Buffer.from(process.env.encryption_iv, "base64");
      if (key.length !== 32) throw new Error("Key must be 32 bytes");
      if (iv.length !== 16) throw new Error("IV must be 16 bytes");
      const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
      let decrypted = decipher.update(
        Buffer.from(userEntity.password, "base64")
      );
      decrypted = Buffer.concat([decrypted, decipher.final()]);
      encrypted = decrypted.toString("utf8").trim();
      encrypted = parseInt(encrypted);
    } catch (error) {
      encrypted = userEntity.password;
    }
    userEntity.password = await encrypted;
    await this.connection.query(
      "update users set users.password = ?,has_mpin = 1 where id = ?",
      [userEntity.password, id]
    );
    return [
      {
        status: "success",
        message: "password updated successfully",
      },
    ];
  }

  async updateStettings(id: number, userEntity: User) {
    await this.connection.query(
      "update users set users.has_mpin = ?,users.notification_enabled = ?,users.lang_id = ? where id = ?",
      [
        userEntity.has_mpin,
        userEntity.notification_enabled,
        userEntity.lang_id,
        id,
      ]
    );
    return [
      {
        status: "success",
        message: "password updated successfully",
      },
    ];
  }

  async updateFCM(userEntity: User) {
    const [check_password] = await this.connection.query(
      "select id,user_id from users where users.username = ? and users.password = ?",
      [userEntity.username, userEntity.password]
    );

    if (check_password) {
      const [chec_fcm_exist] = await this.connection.query(
        "select id from users_authentication where users_authentication.users_id = ?",
        [check_password.id]
      );

      if (chec_fcm_exist) {
        const updateFCM = await this.connection.query(
          `update users_authentication set fcm_token = ? where id = ?`,
          [userEntity.fcm_token, chec_fcm_exist.id]
        );

        return {
          status: "success",
          message: "fcm token updated successfully",
        };
      } else {
        await this.connection.query(
          `insert into users_authentication (users_id,fcm_token) values (?,?)`,
          [check_password.id, userEntity.fcm_token]
        );
        return {
          status: "success",
          message: "fcm token inserted successfully",
        };
      }
    } else {
      return {
        status: "false",
        message: "Enter correct username and mpin",
      };
    }
  }
  async remove(id: number) {
    await this.connection.query("DELETE FROM users WHERE id = ?", [id]);
    return [
      {
        status: "success",
        message: " id: " + id + " deleted successfully",
      },
    ];
  }

  async createToken(username: string, accessToken: any) {
    const decoded = jwt.verify(accessToken, process.env.JWT_SECRET);
    const JWTexpiresIn = process.env.JWT_EXPIRATION;

    delete decoded.iat;
    delete decoded.exp;
    const accessTokens = jwt.sign(decoded, process.env.JWT_SECRET, {
      expiresIn: JWTexpiresIn,
    });
    const [getusername] = await this.connection.query(
      `select id from users where username = ?`,
      [username]
    );
    await this.connection.query(
      `update phr_jwt_token set token = ?,
         expiry = DATE_ADD(NOW(), INTERVAL 7 DAY) where token = ? and user_id = ?`,
      [accessTokens, accessToken, getusername.id]
    );
    return {
      status: "success",
      message: "Token Created",
      accessToken: accessTokens,
    };
  }

  async user_patient_list(userEntity: User) {
    let aa;
    if (userEntity.username.length > 10) {
      aa = userEntity.username.slice(2);
    } else {
      aa = userEntity.username;
    }

    const getProfile = await this.connection.query(
      `select id,patient_name,age,gender, aayush_unique_id,image from patients where mobileno = ?`,
      [aa]
    );

    if (!getProfile || getProfile.length === 0) {
      return [
        {
          status: "failed",
          status_code: 500,
          message: "Patient list not found",
        },
      ];
    }
    return [
      {
        status: "success",
        status_code: 200,
        messege: "patient list retrieved successfully",
        patient_id_list: getProfile,
      },
    ];
  }

  async get_user_id(username: string) {
    const [getusername] = await this.connection.query(
      `select id from users where username = ?`,
      [username]
    );
    return getusername.id;
  }
}
