package repositories

import (
	"fmt"
	"nearle/models"
	"strconv"

	"gorm.io/gorm"
)

type PartnerRepository interface {
	GetActiveRiders(partnerid, aid, uid, tid int) ([]models.RiderInfo, error)
	GetPartners(aid, pid, uid int) ([]models.Partnerinfo, error)
	GetRiderShifts(aid int) ([]models.Ridershifts, error)
	GetLocationConfig(uid, cid int) ([]models.Locationconfigs, error)
	GetRiderLogs(pid, aid int, fdate, tdate string) ([]models.RiderlogDetails, error)
	GetRiderInfo(userid int) (models.RiderInfo, error)
	GetFleetSummary(aid, tid int, fdate, tdate string) (models.FleetSummary, error)
}

type partnerRepository struct {
	db *gorm.DB
}

func NewPartnerRepository(db *gorm.DB) PartnerRepository {
	return &partnerRepository{db: db}
}

func (r *partnerRepository) GetActiveRiders(partnerid, aid, uid, tid int) ([]models.RiderInfo, error) {
	var data []models.RiderInfo
	var q1 string

	const riders = `SELECT DISTINCT b.poolid, a.userid, a.firstname, a.lastname,CONCAT(a.firstname, ' ', a.lastname) AS fullname,a.contactno, a.userfcmtoken, a.partnerid, a.applocationid,
    				c.identificationno, c.registrationno, c.licenseno, c.vehiclename, c.vehicleno,d.shiftid, d.starttime, d.endtime, d.shifthours, d.basefare, d.fuelcharge,e.logdate, 
    				e.login, e.logout, e.workhours, e.shorthours, e.logstatus, a.status,f.locationname AS applocation
					FROM app_users a
					INNER JOIN app_userpools b ON a.userid = b.userid
					INNER JOIN ridersettings c ON a.userid = c.userid
					INNER JOIN ridershifts d ON c.shiftid = d.shiftid
					INNER JOIN (
						SELECT r1.*
						FROM riderlogs r1
						INNER JOIN (
							SELECT userid, MAX(logdate) AS max_logdate
							FROM riderlogs
							WHERE logdate::date = CURRENT_DATE
							GROUP BY userid
						) r2 ON r1.userid = r2.userid AND r1.logdate = r2.max_logdate
					) e ON a.userid = e.userid
					INNER JOIN app_location f ON a.applocationid = f.applocationid
					INNER JOIN app_locationconfig g ON g.applocationid = f.applocationid`

	if aid != 0 {
		q1 = riders + ` WHERE a.configid = 6 AND a.status = 'Active' AND b.onduty = 1 
			AND e.logdate::date = CURRENT_DATE AND e.logstatus = 0 AND a.applocationid = ` + strconv.Itoa(aid)
	} else if partnerid != 0 {
		q1 = riders + ` WHERE a.configid = 6 AND a.status = 'Active' AND b.onduty = 1 
			AND e.logdate::date = CURRENT_DATE AND e.logstatus = 0 AND a.partnerid = ` + strconv.Itoa(partnerid)
	} else if tid != 0 {
		q1 = riders + ` WHERE a.configid = 6 AND a.status = 'Active' AND b.onduty = 1 
			AND e.logdate::date = CURRENT_DATE AND e.logstatus = 0 AND a.tenantid = ` + strconv.Itoa(tid)
	} else {
		q1 = riders + ` WHERE g.status = 'Active' AND a.configid = 6 AND a.status = 'Active' 
			AND b.onduty = 1 AND e.logdate::date = CURRENT_DATE AND e.logstatus = 0 AND g.userid = ` + strconv.Itoa(uid)
	}

	err := r.db.Raw(q1).Find(&data).Error
	if err != nil {
		return nil, err
	}

	return data, nil
}

func (r *partnerRepository) GetPartners(aid, pid, uid int) ([]models.Partnerinfo, error) {
	var data []models.Partnerinfo
	var q1 string
	var args []interface{}

	if pid != 0 {
		q1 = `select partnerid,applocationid,partnertypeid,partnername,primarycontact,primaryemail,
			 contactno,address,suburb,state,city,partnerimage 
			 from partnerinfo where status='Active' and partnerid=?`
		args = append(args, pid)

	} else if aid != 0 {
		q1 = `select partnerid,applocationid,partnertypeid,partnername,primarycontact,primaryemail,
		      contactno,address,suburb,state,city,partnerimage 
			  from partnerinfo where status='Active' and applocationid=?`
		args = append(args, aid)

	} else {
		q1 = `select partnerid,applocationid,partnertypeid,partnername,primarycontact,primaryemail,
		      contactno,address,suburb,state,city,partnerimage 
			  from partnerinfo where status='Active'`
	}

	err := r.db.Raw(q1, args...).Find(&data).Error
	if err != nil {
		return nil, err
	}

	print(q1)
	return data, nil
}

func (r *partnerRepository) GetRiderShifts(aid int) ([]models.Ridershifts, error) {

	var data []models.Ridershifts

	q1 := `Select a.*,concat(a.starttime,'-',a.endtime) as shiftname from ridershifts a where a.applocationid=` + strconv.Itoa(aid)

	err := r.db.Raw(q1).Find(&data).Error

	if err != nil {
		return nil, err
	}

	print(q1)

	return data, nil
}

func (r *partnerRepository) GetLocationConfig(uid, cid int) ([]models.Locationconfigs, error) {

	var data []models.Locationconfigs

	q1 := fmt.Sprintf(`SELECT a.applocationid,a.locationname FROM app_location a 
	inner join app_locationconfig b ON a.applocationid=b.applocationid 
	WHERE b.status='Active' and b.userid=%d`, uid)

	err := r.db.Raw(q1).Find(&data).Error
	if err != nil {
		return nil, err
	}

	print(q1)
	return data, nil
}

func (r *partnerRepository) GetRiderLogs(pid, aid int, fdate, tdate string) ([]models.RiderlogDetails, error) {
	var data []models.RiderlogDetails
	var args []interface{}

	baseQuery := `
		SELECT a.*, b.*, CONCAT(b.firstname,' ',b.lastname) AS username, 
		       COALESCE(SUM(c.breakhours),0) AS breakhours
		FROM riderlogs a
		INNER JOIN app_users b ON a.userid = b.userid
		LEFT JOIN riderbreaks c ON a.logid = c.logid AND a.userid = c.userid
		WHERE 1=1
	`

	if pid != 0 {
		baseQuery += " AND a.partnerid = ?"
		args = append(args, pid)
	}

	if aid != 0 {
		baseQuery += " AND b.applocationid = ?"
		args = append(args, aid)
	}

	if fdate != "" && tdate != "" {
		baseQuery += " AND logdate::date BETWEEN ? AND ?"
		args = append(args, fdate, tdate)
	} else {
		baseQuery += " AND a.logdate::date = CURRENT_DATE"
	}

	baseQuery += " GROUP BY a.userid ORDER BY logid ASC"

	if err := r.db.Raw(baseQuery, args...).Find(&data).Error; err != nil {
		return nil, err
	}

	return data, nil
}

func (r *partnerRepository) GetRiderInfo(userid int) (models.RiderInfo, error) {
	var data models.RiderInfo

	q1 := `SELECT a.userid,a.firstname,a.lastname, CONCAT(a.firstname,' ',a.lastname) as fullname,
			a.partnerid,a.configid,a.contactno,
			a.address,a.suburb,a.city,a.state,a.postcode,a.latitude,a.longitude,
			b.identificationno,b.vehicleno,b.vehiclename,b.licenseno,b.insuranceno,b.insurancedate,
			c.shiftid,c.starttime,c.endtime,c.shifthours,c.basefare,c.additionalcharges,c.orders,c.fuelcharge,a.status,
			a.applocationid,d.locationname as applocation,d.logseconds
			FROM app_users a
			INNER JOIN ridersettings b ON a.userid=b.userid
			INNER JOIN ridershifts c ON b.shiftid=c.shiftid
			INNER JOIN app_location d ON a.applocationid=d.applocationid
			WHERE a.userid = ?`

	if err := r.db.Raw(q1, userid).Scan(&data).Error; err != nil {
		return models.RiderInfo{}, err
	}

	return data, nil
}

func (r *partnerRepository) GetFleetSummary(aid, tid int, fdate, tdate string) (models.FleetSummary, error) {
	var summary models.FleetSummary

	// --- Fleet membership filter (app_users aliased as a) ---
	memberWhere := "a.configid = 6"
	var memberArgs []interface{}
	if aid != 0 {
		memberWhere += " AND a.applocationid = ?"
		memberArgs = append(memberArgs, aid)
	}
	if tid != 0 {
		memberWhere += " AND a.tenantid = ?"
		memberArgs = append(memberArgs, tid)
	}

	countsQuery := `
		SELECT
			COUNT(*) AS totalriders,
			COUNT(*) FILTER (WHERE a.status = 'Active') AS activeriders
		FROM app_users a
		WHERE ` + memberWhere

	if err := r.db.Raw(countsQuery, memberArgs...).Scan(&summary.Counts).Error; err != nil {
		return models.FleetSummary{}, err
	}

	// --- Log-range filter (app_users aliased as b, riderlogs as a) ---
	logWhere := "b.configid = 6"
	var logArgs []interface{}
	if aid != 0 {
		logWhere += " AND b.applocationid = ?"
		logArgs = append(logArgs, aid)
	}
	if tid != 0 {
		logWhere += " AND b.tenantid = ?"
		logArgs = append(logArgs, tid)
	}
	if fdate != "" && tdate != "" {
		logWhere += " AND a.logdate::date BETWEEN ? AND ?"
		logArgs = append(logArgs, fdate, tdate)
	} else {
		logWhere += " AND a.logdate::date = CURRENT_DATE"
	}

	var worked struct {
		Ridersworked int `json:"ridersworked"`
		Totallogins  int `json:"totallogins"`
	}

	workedQuery := `
		SELECT
			COUNT(DISTINCT a.userid) AS ridersworked,
			COUNT(*) AS totallogins
		FROM riderlogs a
		INNER JOIN app_users b ON a.userid = b.userid
		WHERE ` + logWhere

	if err := r.db.Raw(workedQuery, logArgs...).Scan(&worked).Error; err != nil {
		return models.FleetSummary{}, err
	}
	summary.Counts.Ridersworked = worked.Ridersworked
	summary.Counts.Totallogins = worked.Totallogins

	// --- Per-rider breakdown over the range ---
	// Breaks are pre-aggregated per log so the join cannot inflate the work/short-hour sums.
	ridersQuery := `
		SELECT
			b.userid,
			CONCAT(b.firstname, ' ', b.lastname) AS fullname,
			b.contactno,
			b.partnerid,
			b.status,
			rs.vehicleno,
			rs.vehiclename,
			COUNT(DISTINCT a.logdate::date) AS dayslogged,
			COALESCE(SUM(a.workhours), 0) AS totalworkhours,
			COALESCE(SUM(a.shorthours), 0) AS totalshorthours,
			COALESCE(SUM(bk.breakhours), 0) AS totalbreakhours
		FROM riderlogs a
		INNER JOIN app_users b ON a.userid = b.userid
		LEFT JOIN ridersettings rs ON b.userid = rs.userid
		LEFT JOIN (
			SELECT logid, userid, SUM(breakhours) AS breakhours
			FROM riderbreaks
			GROUP BY logid, userid
		) bk ON a.logid = bk.logid AND a.userid = bk.userid
		WHERE ` + logWhere + `
		GROUP BY b.userid, b.firstname, b.lastname, b.contactno, b.partnerid, b.status, rs.vehicleno, rs.vehiclename
		ORDER BY fullname ASC`

	if err := r.db.Raw(ridersQuery, logArgs...).Find(&summary.Riders).Error; err != nil {
		return models.FleetSummary{}, err
	}

	return summary, nil
}
