package domain

import (
	"errors"
	"nearle/db"
	"nearle/models"
	"nearle/utils"
	"strconv"
	"strings"

	"github.com/jinzhu/copier"
)

func CreateTenantUser(data models.Tenants) (bool, error) {

	var seq models.Ordersequences
	var user models.User
	var cust models.Customers
	var custloc models.Customerlocations
	var tcust models.Tenantcustomers

	tx := db.DB.Begin()

	t1 := tx.Create(&data)
	if t1.Error != nil {

		tx.Rollback()
		return false, errors.New("error in tenant creation")
	}

	seq.Tenantid = data.Tenantid

	t2 := tx.Table("ordersequences").Create(&seq)
	if t2.Error != nil {

		tx.Rollback()
		return false, errors.New("error in sequence")
	}

	if err := copier.Copy(&user, &data); err != nil {
		return false, err
	}

	user.Userfcmtoken = data.Tenanttoken
	user.Contactno = data.Primarycontact
	user.Email = data.Primaryemail
	user.Authname = data.Primaryemail
	user.Deviceid = data.Deviceid
	user.Tenantid = data.Tenantid
	user.Locationid = data.Tenantlocations.Locationid
	user.Roleid = 1

	t3 := tx.Table("app_users").Create(&user)
	if t3.Error != nil {

		tx.Rollback()
		return false, errors.New("error in user creation")
	}

	cust.Configid = data.Configid
	cust.Firstname = data.Tenantname
	cust.Email = data.Primaryemail
	cust.Contactno = data.Primarycontact
	cust.Deviceid = data.Deviceid
	cust.Devicetype = data.Devicetype
	cust.Customertoken = data.Tenanttoken
	cust.Profileimage = data.Tenantimage
	cust.Address = data.Address
	cust.Suburb = data.Suburb
	cust.City = data.City
	cust.State = data.State
	cust.Postcode = data.Postcode
	cust.Applocationid = data.Applocationid
	cust.Latitude = data.Latitude
	cust.Longitude = data.Longitude
	cust.Primaryaddress = 1

	cid := CheckCustomer(data.Primarycontact)

	if cid == 0 {

		t4 := tx.Table("customers").Create(&cust)
		if t4.Error != nil {

			tx.Rollback()
			return false, errors.New("error in customer creation")
		}

		if err := copier.Copy(&custloc, &cust); err != nil {
			return false, err
		}

		t5 := tx.Table("customerlocations").Create(&custloc)
		if t5.Error != nil {

			tx.Rollback()
			return false, errors.New("error in customer location")
		}

	} else {

		t1 := tx.Table("customers").Where("customerid=?", cid).Updates(&cust)
		if t1.Error != nil {

			tx.Rollback()
			return false, errors.New("error in customer creation")
		}

		if err := copier.Copy(&custloc, &cust); err != nil {
			return false, err
		}

		t2 := tx.Table("customerlocations").Where("customerid=?", cid).Updates(&custloc)
		if t2.Error != nil {

			tx.Rollback()
			return false, errors.New("error in customer location")
		}

	}

	tcust.Customerid = cust.Customerid
	tcust.Tenantid = data.Tenantid
	tcust.Locationid = data.Tenantlocations.Locationid

	t6 := tx.Table("tenantcustomers").Create(&tcust)
	if t6.Error != nil {

		tx.Rollback()
		return false, errors.New("error in tenant customer")
	}

	err := tx.Commit().Error

	if err != nil {

		return false, errors.New("error in tenant creation")

	}

	return true, nil

}

func UpdateTenant(input models.Tenants) error {

	tx := db.DB.Begin()

	t1 := tx.Where("tenantid=?", input.Tenantid).Updates(&input)
	if t1.Error != nil {

		tx.Rollback()
		return t1.Error
	}

	err := tx.Commit().Error
	if err != nil {

		return err

	}

	return nil

}

func UpdateLocation(input models.Tenantlocations) error {

	tx := db.DB.Begin()

	t1 := tx.Where("locationid=?", input.Locationid).Updates(&input)
	if t1.Error != nil {

		tx.Rollback()
		return t1.Error
	}
	err := tx.Commit().Error
	if err != nil {

		return err

	}

	return nil

}

func CreateLocation(data models.Tenantlocations) error {

	var cust models.Customers
	var tcust models.Tenantcustomers
	var custloc models.Customerlocations

	tx := db.DB.Begin()

	t1 := tx.Create(&data)
	if t1.Error != nil {

		tx.Rollback()
		return t1.Error
	}

	cust.Firstname = data.Locationname
	cust.Email = data.Email
	cust.Contactno = data.Contactno
	cust.Address = data.Address
	cust.Suburb = data.Suburb
	cust.City = data.City
	cust.State = data.State
	cust.Postcode = data.Postcode
	cust.Applocationid = data.Applocationid
	cust.Latitude = data.Latitude
	cust.Longitude = data.Longitude
	cust.Primaryaddress = 0

	t2 := tx.Table("customers").Create(&cust)
	if t2.Error != nil {

		tx.Rollback()
		return t2.Error
	}

	if err := copier.Copy(&custloc, &cust); err != nil {
		return err
	}

	t3 := tx.Table("customerlocations").Create(&custloc)
	if t3.Error != nil {

		tx.Rollback()
		return t3.Error
	}

	tcust.Customerid = cust.Customerid
	tcust.Tenantid = data.Tenantid
	tcust.Locationid = data.Locationid
	tcust.Moduleid = data.Moduleid

	t4 := tx.Table("tenantcustomers").Create(&tcust)
	if t4.Error != nil {

		tx.Rollback()
		return t4.Error
	}
	err := tx.Commit().Error
	if err != nil {

		return err

	}

	return nil

}

func Checktenantbyno(cno string) int {

	var id int

	q1 := "select tenantid from tenants where primarycontact='" + cno + `'`

	db.DB.Raw(q1).Find(&id)
	return id

}

func GetTeanantById(tid int) models.Tenantinfo {

	var data models.Tenantinfo

	// q1 := `SELECT a.*,b.categoryid,b.subcategoryid,c.subcategoryname,b.moduleid,d.locationid,d.locationname FROM
	// 	tenants a
	// 	INNER JOIN tenantsubscriptions b ON a.tenantid=b.tenantid
	// 	INNER JOIN  app_subcategory c ON c.subcategoryid=b.subcategoryid
	// 	INNER JOIN tenantlocations d ON d.tenantid=a.tenantid
	// 	where a.tenantid=?`

	q1 := `SELECT a.*,b.categoryname,c.locationname as applocation,d.allocationid as allocationmode,e.typename AS allocationtype,e.mapid as allocationid,f.locationid,
			f.locationname, g.slab, g.pricingdate, g.baseprice, g.minkm, g.priceperkm, g.maxkm, g.orders, g.othercharges, g.surgecharges
			FROM tenants a 
			INNER JOIN  app_category b ON a.categoryid=b.categoryid
			INNER JOIN app_location c ON a.applocationid=c.applocationid
			LEFT JOIN partnerinfo d ON a.partnerid=d.partnerid
			LEFT JOIN app_types e ON d.allocationid=e.apptypeid
			LEFT JOIN tenantlocations f ON a.tenantid=f.tenantid
			LEFT JOIN tenantpricing g ON a.tenantid=g.tenantid
			where a.tenantid=?`

	utils.Logger.Debugf("Query: %s", q1)

	db.DB.Raw(q1, tid).Find(&data)

	return data

}

func GetTeanantPricing(tid, aid int) models.Tenantpricing {

	var data models.Tenantpricing
	var q1 string

	if tid != 0 {

		q1 = `SELECT * FROM tenantpricing WHERE pricingdate = (SELECT MAX(pricingdate) FROM tenantpricing where tenantid=` + strconv.Itoa(tid) + `) AND tenantid=? order by tenantpricingid desc`

	}

	utils.Logger.Debugf("Query: %s", q1)

	db.DB.Raw(q1, tid).Find(&data)

	return data

}

func GetPricinglist(tid int) []models.Tenantpricing {

	var data []models.Tenantpricing

	q1 := `SELECT *
	FROM tenantpricing
	WHERE  tenantid=? order by pricingdate desc`

	db.DB.Raw(q1, tid).Find(&data)

	return data

}

func Getalltenants(pageno, pagesize, aid, moduleid int, status, tenanttype, keyword string) []models.Tenantinfo {

	offset := (pageno - 1) * pagesize

	var data []models.Tenantinfo

	base := `
        SELECT a.*, b.categoryname, c.slab, c.pricingdate, c.baseprice, c.minkm, 
	       c.priceperkm, c.maxkm, c.orders, 
	       c.othercharges, c.surgecharges
        FROM tenants a
		LEFT JOIN app_category b ON a.categoryid = b.categoryid
		LEFT JOIN (
			SELECT DISTINCT ON (tenantid) *
			FROM tenantpricing
			ORDER BY tenantid, pricingdate DESC
		) c ON a.tenantid = c.tenantid
        WHERE 1 = 1
    `

	var (
		conds  []string
		params []interface{}
	)

	switch strings.ToLower(status) {
	case "active":
		conds = append(conds, "a.approved = 1 AND a.status = 'Active'")
	case "inactive":
		conds = append(conds, "a.approved = 1 AND a.status = 'InActive'")
	case "pending":
		conds = append(conds, "a.approved = 0")
	}

	if aid != 0 {
		conds = append(conds, "a.applocationid = ?")
		params = append(params, aid)
	}

	if moduleid != 0 {
		conds = append(conds, "a.moduleid = ?")
		params = append(params, moduleid)
	}

	if tenanttype != "" {
		conds = append(conds, "a.tenanttype = ?")
		params = append(params, tenanttype)
	}

	if keyword != "" {
		kw := "%" + strings.ToLower(keyword) + "%"
		conds = append(conds,
			"(LOWER(a.tenantname) LIKE ? OR LOWER(a.primarycontact) LIKE ?)")
		params = append(params, kw, kw)
	}

	if len(conds) > 0 {
		base += " AND " + strings.Join(conds, " AND ")
	}

	base += " ORDER BY a.tenantid DESC LIMIT ? OFFSET ?"
	params = append(params, pagesize, offset)

	print(base, params)
	db.DB.Raw(base, params...).Find(&data)

	return data
}

func GetCustomerLocations(customerID int) models.CustomerTenantResponse {
	var customer models.Customers

	// get customer
	db.DB.Table("customers").
		Where("customerid = ?", customerID).
		First(&customer)

	// get locations
	locations := []models.LocationDetails{}

	query := `
		SELECT 
			c.locationid,c.locationname,c.tenantid,b.tenantname,c.address,c.email,c.contactno,c.applocationid,c.suburb,c.city,c.latitude,c.longitude,c.postcode
		FROM tenantcustomers a
		Left join tenants b ON a.tenantid = b.tenantid
		LEFT JOIN tenantlocations c ON a.locationid = c.locationid
		WHERE a.customerid = ?
	`

	db.DB.Raw(query, customerID).Scan(&locations)

	// print(customer, locations)

	return models.CustomerTenantResponse{
		Customer:        customer,
		Tenantlocations: locations,
	}
}

func CreateTenantLocation(data models.Tenantlocations) error {
	var user models.Tenantuser

	tx := db.DB.Begin()

	// 🔧 Set status BEFORE insert
	data.Status = "InActive"

	// Step 1: Insert into tenantlocations
	if err := tx.Create(&data).Error; err != nil {
		tx.Rollback()
		return err
	}

	// Step 2: Insert into app_users
	user.Authname = data.Email
	user.Firstname = data.Locationname
	user.Email = data.Email
	user.Contactno = data.Contactno
	user.Address = data.Address
	user.Suburb = data.Suburb
	user.City = data.City
	user.State = data.State
	user.Postcode = data.Postcode
	user.Partnerid = data.Partnerid
	user.Tenantid = data.Tenantid
	user.Locationid = data.Locationid
	user.Applocationid = data.Applocationid
	user.Configid = 1
	user.Status = "InActive"
	user.Roleid = 0
	user.Authmode = 0
	user.Password = ""
	user.Dialcode = "+91"

	if err := tx.Table("app_users").Create(&user).Error; err != nil {
		tx.Rollback()
		return err
	}

	// Commit
	if err := tx.Commit().Error; err != nil {
		return err
	}

	return nil
}

func UpdateTenantLocation(input models.Tenantlocations) error {
	tx := db.DB.Begin()

	t1 := tx.Where("locationid=?", input.Locationid).Updates(&input)
	if t1.Error != nil {

		tx.Rollback()
		return t1.Error
	}

	err := tx.Commit().Error
	if err != nil {

		return err

	}

	return nil
}

func FetchLocationSummary(tenantID int) models.LocationSummary {
	var summary models.LocationSummary

	db.DB.Raw(`
		SELECT 
			SUM(CASE WHEN status = 'Active' THEN 1 ELSE 0 END) AS active_count,
			SUM(CASE WHEN status = 'InActive' THEN 1 ELSE 0 END) AS inactive_count,
			COUNT(*) AS total_count
		FROM tenantlocations
		WHERE tenantid = ?
	`, tenantID).Scan(&summary)

	return summary
}

func FetchTenantStaffSummary(tenantID int) models.TenantUserSummary {
	var summary models.TenantUserSummary

	query := `
		SELECT 
			SUM(CASE WHEN a.status = 'Active' THEN 1 ELSE 0 END) AS active_count,
			SUM(CASE WHEN b.status = 'InActive' THEN 1 ELSE 0 END) AS inactive_count,
			COUNT(*) AS total_count
		FROM tenantstaffs a
		JOIN app_users b ON a.userid = b.userid
		WHERE a.tenantid = ? AND b.roleid = 2
	`

	db.DB.Raw(query, tenantID).Scan(&summary)
	return summary
}

func FetchTenantRiderSummary(tenantID int) models.TenantUserSummary {
	var summary models.TenantUserSummary

	query := `
		SELECT 
			SUM(CASE WHEN a.status = 'Active' THEN 1 ELSE 0 END) AS active_count,
			SUM(CASE WHEN a.status = 'InActive' THEN 1 ELSE 0 END) AS inactive_count,
			COUNT(*) AS total_count
		FROM tenantstaffs a
		JOIN app_users b ON a.userid = b.userid
		WHERE a.tenantid = ? AND b.roleid = 3
	`

	db.DB.Raw(query, tenantID).Scan(&summary)
	return summary
}

func CreateTenantPromotion(promo *models.Tenantpromotions) error {

	// convert []string to comma-separated string
	if len(promo.Locationid) > 0 {
		promo.LocationidStr = strings.Join(promo.Locationid, ",")
	}

	tx := db.DB.Begin()

	if err := tx.Table("tenantpromotions").Create(promo).Error; err != nil {
		tx.Rollback()
		return err
	}

	return tx.Commit().Error
}

func GetTenantPromotions(tid int, lid string) []models.Tenantpromotions {

	var result []models.Tenantpromotions

	query := `
        SELECT 
            promotionid, promotiontypeid, tenantid,
            locationid, applocationid, moduleid, categoryid,
            promoname, promocode, description, product, productimage,
            promoamount, promovalue, purchasevalue, startdate, enddate
        FROM tenantpromotions
        WHERE tenantid = ? 
          AND moduleid = 2
          AND FIND_IN_SET(?, locationid)
    `

	db.DB.Raw(query, tid, lid).Scan(&result)

	// Convert location string → slice
	for i := range result {
		if result[i].LocationidStr != "" {
			result[i].Locationid = strings.Split(result[i].LocationidStr, ",")
		} else {
			result[i].Locationid = []string{}
		}
	}

	return result
}
