import { api as apiClient } from "@/auth/http";
import { URL_CONSTANTS } from "@/constants/URLS";
import type {
  Company,
  CompanyChangeRequest,
  CompanyListFilter,
  CompanyProfile,
  CompanyStats,
  CustomerBooking,
  CustomerDocument,
  CustomerPayment,
  CustomerResetTarget,
  PaginatedCompanies,
  ProfileStatus,
  ResetChannel,
  ResetPasswordResult,
} from "@/types/customer";

const cleanParams = (params: object) =>
  Object.fromEntries(
    Object.entries(params).filter(
      ([, value]) => value !== undefined && value !== "" && value !== null,
    ),
  );

/** Lift attributes JSONB into the flat contact/manager fields the UI reads. */
function mapCompany(dto: Record<string, unknown>): Company {
  const attrs = (dto.attributes as Record<string, unknown> | null) ?? {};
  return {
    ...(dto as unknown as Company),
    companyProfiles: (dto.companyProfiles as Company["companyProfiles"]) ?? [],
    contactPersonName: (attrs.contactPersonName as string | null) ?? null,
    contactPersonPhone: (attrs.contactPersonPhone as string | null) ?? null,
    generalManagerName: (attrs.generalManagerName as string | null) ?? null,
    generalManagerEmail: (attrs.generalManagerEmail as string | null) ?? null,
    generalManagerPhone: (attrs.generalManagerPhone as string | null) ?? null,
    poaName: (attrs.poaName as string | null) ?? null,
    poaEmail: (attrs.poaEmail as string | null) ?? null,
    poaPhone: (attrs.poaPhone as string | null) ?? null,
    poaLocation: (attrs.poaLocation as string | null) ?? null,
    poaAddress: (attrs.poaAddress as string | null) ?? null,
  };
}

export const customersService = {
  stats(): Promise<CompanyStats> {
    return apiClient
      .get<CompanyStats>(URL_CONSTANTS.COMPANIES.STATS)
      .then((r) => r.data);
  },

  list(filter: CompanyListFilter): Promise<PaginatedCompanies> {
    return apiClient
      .get<{ items: Record<string, unknown>[]; total: number }>(
        URL_CONSTANTS.COMPANIES.BASE,
        { params: cleanParams(filter) },
      )
      .then((r) => ({
        items: r.data.items.map(mapCompany),
        total: r.data.total,
      }));
  },

  getById(id: string): Promise<Company | undefined> {
    return apiClient
      .get<Record<string, unknown>>(URL_CONSTANTS.COMPANIES.BY_ID(id))
      .then((r) => mapCompany(r.data));
  },

  bookingsFor(companyId: string): Promise<CustomerBooking[]> {
    return apiClient
      .get<CustomerBooking[]>(
        URL_CONSTANTS.COMPANIES.BOOKINGS_CUSTOMER_VIEW(companyId),
      )
      .then((r) => r.data);
  },

  documentsFor(companyId: string): Promise<CustomerDocument[]> {
    return apiClient
      .get<CustomerDocument[]>(URL_CONSTANTS.COMPANIES.DOCUMENTS(companyId))
      .then((r) => r.data);
  },

  paymentsFor(companyId: string): Promise<CustomerPayment[]> {
    return apiClient
      .get<CustomerPayment[]>(
        URL_CONSTANTS.COMPANIES.PAYMENTS_CUSTOMER_VIEW(companyId),
      )
      .then((r) => r.data);
  },

  /**
   * The IAM account a reset link would go to. Read before offering the action
   * so staff see the credentials the link actually reaches, not the company's
   * business contact details.
   */
  resetTarget(companyId: string): Promise<CustomerResetTarget> {
    return apiClient
      .get<CustomerResetTarget>(URL_CONSTANTS.COMPANIES.RESET_TARGET(companyId))
      .then((r) => r.data);
  },

  /**
   * Send a password-reset link to the company's primary contact. Staff never
   * receive a credential — the customer opens the link and sets their own
   * password.
   */
  resetPassword(
    companyId: string,
    channel: ResetChannel,
  ): Promise<ResetPasswordResult> {
    return apiClient
      .post<ResetPasswordResult>(
        URL_CONSTANTS.COMPANIES.RESET_PASSWORD(companyId),
        { channel },
      )
      .then((r) => r.data);
  },

  setProfileStatus(
    profileId: string,
    status: ProfileStatus,
    note?: string,
  ): Promise<CompanyProfile> {
    return apiClient
      .patch<CompanyProfile>(
        URL_CONSTANTS.COMPANIES.PROFILE_STATUS(profileId),
        { status, note },
      )
      .then((r) => r.data);
  },

  /** Approve / change a company's status (e.g. pending → active). */
  setCompanyStatus(companyId: string, status: string): Promise<unknown> {
    return apiClient
      .patch(URL_CONSTANTS.COMPANIES.BY_ID(companyId), { status })
      .then((r) => r.data);
  },

  /** List a company's profile-edit change requests (newest first). */
  changeRequests(companyId: string): Promise<CompanyChangeRequest[]> {
    return apiClient
      .get<CompanyChangeRequest[]>(
        URL_CONSTANTS.COMPANIES.CHANGE_REQUESTS(companyId),
      )
      .then((r) => r.data);
  },

  /** Approve a pending change request — applies the proposed changes. */
  approveChangeRequest(id: string): Promise<CompanyChangeRequest> {
    return apiClient
      .post<CompanyChangeRequest>(
        URL_CONSTANTS.COMPANIES.CHANGE_REQUEST_APPROVE(id),
      )
      .then((r) => r.data);
  },

  /** Reject a pending change request with a note. */
  rejectChangeRequest(id: string, note: string): Promise<CompanyChangeRequest> {
    return apiClient
      .post<CompanyChangeRequest>(
        URL_CONSTANTS.COMPANIES.CHANGE_REQUEST_REJECT(id),
        { note },
      )
      .then((r) => r.data);
  },

  /**
   * Ask the customer to correct one uploaded document. Narrower than rejecting
   * the whole role: the customer keeps their other documents and only re-uploads
   * this one, but the role cannot be approved until they do.
   */
  requestDocumentChange(
    fileId: string,
    note: string,
  ): Promise<CustomerDocument> {
    return apiClient
      .post<CustomerDocument>(
        URL_CONSTANTS.COMPANIES.DOCUMENT_REQUEST_CHANGE(fileId),
        { note },
      )
      .then((r) => r.data);
  },
};
