package subdistrict

import (
	"cargo-erp-backend/internal/handlers/dto"
	subdistrictimporter "cargo-erp-backend/internal/importers/subdistrict"
	"cargo-erp-backend/internal/usecases"
	"cargo-erp-backend/pkg/helpers"
	"cargo-erp-backend/pkg/importer"
	"cargo-erp-backend/pkg/response"
	"net/http"

	"github.com/gin-gonic/gin"
)

type SubdistrictHandlerInterface interface {
	Router()
}

type SubdistrictHandler struct {
	Helper helpers.HelperInterface
	Group  *gin.RouterGroup
}

func NewSubdistrictHandler(helper helpers.HelperInterface, g *gin.RouterGroup) SubdistrictHandlerInterface {
	return &SubdistrictHandler{Helper: helper, Group: g}
}

func (h *SubdistrictHandler) Router() {
	r := h.Group.Group("subdistricts")
	{
		r.GET("/", h.GetAll)
		r.POST("/list", h.GetList)
		r.GET("/:id", h.GetByID)
		r.POST("/", h.Create)
		r.PUT("/:id", h.Update)
		r.DELETE("/:id", h.Delete)
		r.GET("/template", h.Template)
		r.POST("/import", h.Import)
		r.POST("/import/stop", h.ImportStop)
		r.GET("/import/status/:jobId", h.ImportStatus)
	}
}

func (h *SubdistrictHandler) GetAll(c *gin.Context) {
	userid, err := h.Helper.GetAuthInfo(c.GetString("auth"))
	if err != nil {
		response.Error(c, http.StatusUnauthorized, err.Error())
		return
	}
	var req dto.SubdistrictFilterAllRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		response.Error(c, http.StatusBadRequest, err.Error())
		return
	}
	u := usecases.NewSubdistrictUsecase(h.Helper, *userid)
	subdistricts, _, err := u.GetAll(req)
	if err != nil {
		response.Error(c, http.StatusInternalServerError, err.Error())
		return
	}
	var responseDTO = make([]dto.CreateSubdistrictResponse, 0)
	for _, v := range subdistricts {
		var DTO dto.CreateSubdistrictResponse
		h.Helper.MapStructToStruct(v, "json", &DTO, "json")
		responseDTO = append(responseDTO, DTO)
	}
	response.Success(c, responseDTO)
}

func (h *SubdistrictHandler) GetList(c *gin.Context) {
	userid, err := h.Helper.GetAuthInfo(c.GetString("auth"))
	if err != nil {
		response.Error(c, http.StatusUnauthorized, err.Error())
		return
	}

	var req dto.DataTableRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, http.StatusBadRequest, "Request Format request invalid")
		return
	}
	u := usecases.NewSubdistrictUsecase(h.Helper, *userid)
	res, err := u.GetList(req)
	if err != nil {
		response.Error(c, http.StatusInternalServerError, err.Error())
		return
	}
	response.Success(c, res)
	return
}

func (h *SubdistrictHandler) GetByID(c *gin.Context) {
	userid, err := h.Helper.GetAuthInfo(c.GetString("auth"))
	if err != nil {
		response.Error(c, http.StatusUnauthorized, err.Error())
		return
	}
	id := c.Param("id")

	u := usecases.NewSubdistrictUsecase(h.Helper, *userid)
	subdistrict, err := u.GetByID(id)
	if err != nil {
		response.Error(c, http.StatusNotFound, "subdistrict not found")
		return
	}

	response.Success(c, subdistrict)
}

func (h *SubdistrictHandler) Create(c *gin.Context) {
	var req dto.CreateSubdistrictRequest
	if err := c.BindJSON(&req); err != nil {
		response.Error(c, http.StatusBadRequest, err.Error())
		return
	}
	userid, err := h.Helper.GetAuthInfo(c.GetString("auth"))
	if err != nil {
		response.Error(c, http.StatusUnauthorized, err.Error())
		return
	}
	var merchantid *string = nil
	if userid.UsersRole_Relation == nil || userid.UsersRole_Relation.RoleKey != "SPM" {
		merchantid = userid.MerchantID
	}
	createdBy := userid.ID

	u := usecases.NewSubdistrictUsecase(h.Helper, *userid)
	subdistrict, err := u.Create(req.Name, req.ProvinceID, req.CityID, req.DistrictID, createdBy, merchantid)
	if err != nil {
		response.Error(c, http.StatusInternalServerError, err.Error())
		return
	}
	var responseDTO dto.CreateSubdistrictResponse
	h.Helper.MapStructToStruct(subdistrict, "json", &responseDTO, "json")
	response.Created(c, responseDTO)
}

func (h *SubdistrictHandler) Update(c *gin.Context) {
	id := c.Param("id")

	var req dto.UpdateSubdistrictRequest
	if err := c.BindJSON(&req); err != nil {
		response.Error(c, http.StatusBadRequest, err.Error())
		return
	}
	userid, err := h.Helper.GetAuthInfo(c.GetString("auth"))
	if err != nil {
		response.Error(c, http.StatusUnauthorized, err.Error())
		return
	}
	updatedBy := userid.ID

	u := usecases.NewSubdistrictUsecase(h.Helper, *userid)
	subdistrict, err := u.Update(id, req.Name, req.ProvinceID, req.CityID, req.DistrictID, updatedBy)
	if err != nil {
		response.Error(c, http.StatusInternalServerError, err.Error())
		return
	}
	var responseDTO dto.CreateSubdistrictResponse
	h.Helper.MapStructToStruct(subdistrict, "json", &responseDTO, "json")
	response.Success(c, responseDTO)
}

func (h *SubdistrictHandler) Delete(c *gin.Context) {
	userid, err := h.Helper.GetAuthInfo(c.GetString("auth"))
	if err != nil {
		response.Error(c, http.StatusUnauthorized, err.Error())
		return
	}
	id := c.Param("id")
	u := usecases.NewSubdistrictUsecase(h.Helper, *userid)
	if err := u.Delete(id); err != nil {
		response.Error(c, http.StatusInternalServerError, err.Error())
		return
	}

	response.Success(c, map[string]interface{}{"message": "subdistrict deleted"})
}

func (h *SubdistrictHandler) Template(c *gin.Context) {
	userid, err := h.Helper.GetAuthInfo(c.GetString("auth"))
	if err != nil {
		response.Error(c, http.StatusUnauthorized, err.Error())
		return
	}
	handler := subdistrictimporter.NewSubdistrictImportHandler(*userid, h.Helper)
	imp := importer.NewImporter(h.Helper, handler)
	imp.ServeTemplate(c.Writer)
}

func (h *SubdistrictHandler) Import(c *gin.Context) {
	userid, err := h.Helper.GetAuthInfo(c.GetString("auth"))
	if err != nil {
		response.Error(c, http.StatusUnauthorized, err.Error())
		return
	}

	file, header, err := c.Request.FormFile("file")
	if err != nil {
		response.Error(c, http.StatusBadRequest, "File is required")
		return
	}
	defer file.Close()

	handler := subdistrictimporter.NewSubdistrictImportHandler(*userid, h.Helper)
	imp := importer.NewImporter(h.Helper, handler)

	result, err := imp.Process(file, userid.ID, header.Filename)
	if err != nil {
		response.Error(c, http.StatusBadRequest, err.Error())
		return
	}

	var importLogs []dto.ImportLog
	for _, l := range result.Logs {
		importLogs = append(importLogs, dto.ImportLog{
			Row:     l.Row,
			Status:  l.Status,
			Data:    l.Data,
			Message: l.Message,
		})
	}

	response.Success(c, dto.ImportSubdistrictResponse{
		JobID:     result.JobID,
		TotalRows: result.TotalRows,
		Imported:  result.Imported,
		Skipped:   result.Skipped,
		Logs:      importLogs,
		Errors:    result.Errors,
		IsAsync:   result.IsAsync,
		Message:   result.Message,
	})
}

func (h *SubdistrictHandler) ImportStatus(c *gin.Context) {
	userid, err := h.Helper.GetAuthInfo(c.GetString("auth"))
	if err != nil {
		response.Error(c, http.StatusUnauthorized, err.Error())
		return
	}
	jobId := c.Param("jobId")

	handler := subdistrictimporter.NewSubdistrictImportHandler(*userid, h.Helper)
	imp := importer.NewImporter(h.Helper, handler)

	job, logs, err := imp.GetJobStatus(jobId)
	if err != nil {
		response.Error(c, http.StatusNotFound, "Job not found")
		return
	}

	response.Success(c, map[string]interface{}{
		"job":  job,
		"logs": logs,
	})
}

func (h *SubdistrictHandler) ImportStop(c *gin.Context) {
	userid, err := h.Helper.GetAuthInfo(c.GetString("auth"))
	if err != nil {
		response.Error(c, http.StatusUnauthorized, err.Error())
		return
	}

	var req dto.StopImportRequest
	if err := c.BindJSON(&req); err != nil {
		response.Error(c, http.StatusBadRequest, "job_id is required")
		return
	}

	handler := subdistrictimporter.NewSubdistrictImportHandler(*userid, h.Helper)
	imp := importer.NewImporter(h.Helper, handler)

	if err := imp.StopJob(req.JobID); err != nil {
		response.Error(c, http.StatusBadRequest, err.Error())
		return
	}

	response.Success(c, map[string]interface{}{"message": "Job stopped"})
}
