package com.kpaudel.controller;
import com.kpaudel.model.ApplicationStatus;
import com.kpaudel.model.Company;
import com.kpaudel.model.JobApplication;
import com.kpaudel.repository.CompanyRepository;
import com.kpaudel.repository.JobApplicationRepository;
import com.kpaudel.service.JobService;
import com.opencsv.CSVWriter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ContentDisposition;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:3000") // frontend dev CORS
public class ApiController {
private final JobService service;
private final CompanyRepository companyRepo;
private final JobApplicationRepository jobRepo;
public ApiController(JobService service, CompanyRepository companyRepo, JobApplicationRepository jobRepo) {
this.service = service;
this.companyRepo = companyRepo;
this.jobRepo = jobRepo;
}
@GetMapping("/jobs")
public List<JobApplication> listJobs(@RequestParam Optional<ApplicationStatus> status) {
return status.map(jobRepo::findByStatus).orElse(jobRepo.findAll());
}
@GetMapping("/jobs/{id}")
public ResponseEntity<JobApplication> getJob(@PathVariable UUID id) {
return this.jobRepo.findById(id).map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping("/jobs")
public JobApplication createJob(@RequestBody JobApplication job) {
return this.service.create(job.getCompany().getId(), job);
}
@PutMapping("/jobs/{id}")
public ResponseEntity<JobApplication> updateJob(@PathVariable UUID id, @RequestBody JobApplication updated) {
return jobRepo.findById(id)
.map(existing -> {
updated.setId(id);
return ResponseEntity.ok(jobRepo.save(updated));
})
.orElse(ResponseEntity.notFound().build());
}
@PatchMapping("/jobs/{id}/status")
public JobApplication updateStatus(@PathVariable UUID id, @RequestBody Map<String, String> body) {
ApplicationStatus status = ApplicationStatus.valueOf(body.get("status"));
return service.updateStatus(id, status);
}
@DeleteMapping("/jobs/{id}")
public ResponseEntity<Void> deleteJob(@PathVariable UUID id) {
if (jobRepo.existsById(id)) {
jobRepo.deleteById(id);
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
@GetMapping("/companies")
public List<Company> listCompanies() {
return this.companyRepo.findAll();
}
@GetMapping("/companies/{id}")
public ResponseEntity<Company> getCompany(@PathVariable UUID id) {
return companyRepo.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@GetMapping("/companies/{id}/jobs")
public List<JobApplication> listJobsByCompany(@PathVariable UUID id) {
return jobRepo.findByCompanyId(id);
}
@PostMapping("/companies")
public Company createCompany(@RequestBody Company company) {
return this.companyRepo.save(company);
}
@PutMapping("/companies/{id}")
public ResponseEntity<Company> updateCompany(@PathVariable UUID id, @RequestBody Company updated) {
return companyRepo.findById(id)
.map(existing -> {
updated.setId(id);
return ResponseEntity.ok(companyRepo.save(updated));
})
.orElse(ResponseEntity.notFound().build());
}
@DeleteMapping("/companies/{id}")
public ResponseEntity<Void> deleteCompany(@PathVariable UUID id) {
if (companyRepo.existsById(id)) {
companyRepo.deleteById(id);
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
@GetMapping("/jobs/export")
public ResponseEntity<byte[]> exportJobs() throws IOException {
List<JobApplication> jobs = this.jobRepo.findAll();
ByteArrayOutputStream out = new ByteArrayOutputStream();
CSVWriter writer = new CSVWriter(new java.io.OutputStreamWriter(out));
//Add headers
writer.writeNext(new String[]{"ID", "Role", "Company","JobUrl", "Applied Date", "Source", "Salary Expectation","Status", "Location", "Last Updated", "Notes"});
//Add Data
for (JobApplication job : jobs) {
writer.writeNext(new String[]{
job.getId().toString(),
job.getRole(),
job.getCompany().getName(),
job.getJobUrl(),
job.getAppliedDate().toString(),
job.getSource(),
job.getSalaryExpectation(),
job.getStatus().name(),
job.getLocation(),
job.getLastUpdated().toString(),
job.getNotes()
});
}
writer.close();
byte[] data = out.toByteArray();
String timestamp = java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("text/csv"));
headers.setContentDisposition(ContentDisposition.attachment().filename("jobs_" + timestamp + ".csv").build());
return new ResponseEntity<>(data, headers, HttpStatus.OK);
}
@GetMapping("/companies/export")
public ResponseEntity<byte[]> exportCompanies() throws IOException {
List<Company> companies = this.companyRepo.findAll();
ByteArrayOutputStream out = new ByteArrayOutputStream();
CSVWriter writer = new CSVWriter(new java.io.OutputStreamWriter(out));
//Add headers
writer.writeNext(new String[]{"ID", "Name", "Website", "Notes"});
//Add Data
for (Company company : companies) {
writer.writeNext(new String[]{
company.getId().toString(),
company.getName(),
company.getWebsite(),
company.getNotes()
});
}
writer.close();
byte[] data = out.toByteArray();
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("text/csv"));
headers.setContentDisposition(ContentDisposition.attachment().filename("companies_" + timestamp + ".csv").build());
return new ResponseEntity<>(data, headers, HttpStatus.OK);
}
}