package tutorial.rest.mvc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import tutorial.core.models.entities.Account;
import tutorial.core.services.AccountService;
import tutorial.core.services.exceptions.AccountExistsException;
import tutorial.core.services.util.AccountList;
import tutorial.rest.exceptions.ConflictException;
import tutorial.rest.resources.AccountListResource;
import tutorial.rest.resources.AccountResource;
import tutorial.rest.resources.asm.AccountListResourceAsm;
import tutorial.rest.resources.asm.AccountResourceAsm;
import java.util.ArrayList;
import java.util.Arrays;
import org.springframework.security.access.prepost.PreAuthorize;
import tutorial.core.services.exceptions.InvalidAccountException;


/**
 * 
 * @author Xavier
 */
@Controller
@RequestMapping("/rest/accounts")
public class AccountController {
    private AccountService accountService;

    /**
     *
     * @param accountService
     */
    @Autowired
    public AccountController(AccountService accountService) {
        this.accountService = accountService;
    }
    /**
     * Returns a List of all accounts
     * @param name if this parameter isn't empty, return the account the matches this name
     * @return a List of accounts or a single account
     */
    @RequestMapping(method = RequestMethod.GET)
    @PreAuthorize("permitAll")
    public ResponseEntity<AccountListResource> findAllAccounts(@RequestParam(value="name", required = false) String name) {
        AccountList list = null;
        if(name == null) {
            list = accountService.findAllAccounts();
        } else {
            Account account = accountService.findByAccountName(name);
            if(account == null) {
                list = new AccountList(new ArrayList<Account>());
            } else {
                list = new AccountList(Arrays.asList(account));
            }
        }
        AccountListResource res = new AccountListResourceAsm().toResource(list);
        return new ResponseEntity<AccountListResource>(res, HttpStatus.OK);
    }

    /**
     * Adds one account to the database
     * @param sentAccount the values that the created account will have
     * @return returns the created account
     */
    @RequestMapping(method = RequestMethod.POST)
    @PreAuthorize("permitAll")
    public ResponseEntity<AccountResource> createAccount(
            @RequestBody AccountResource sentAccount
    ) {
        try {
            Account createdAccount = accountService.createAccount(sentAccount.toAccount());
            AccountResource res = new AccountResourceAsm().toResource(createdAccount);
            return new ResponseEntity<AccountResource>(res, HttpStatus.CREATED);
        }catch(AccountExistsException exception) {
            throw new ConflictException(exception);
        }catch(InvalidAccountException exception) {
            throw new ConflictException(exception);
        }
    }

    /**
     * Returns the account with the given Id
     * @param accountId the given Id
     * @return the account with the given Id or a NOT_FOUND error
     */
    @RequestMapping( value="/{accountId}",
                method = RequestMethod.GET)
    @PreAuthorize("permitAll")
    public ResponseEntity<AccountResource> getAccount(
            @PathVariable Long accountId
    ) {
        Account account = accountService.findAccount(accountId);
        if(account != null)
        {
            AccountResource res = new AccountResourceAsm().toResource(account);
            return new ResponseEntity<AccountResource>(res, HttpStatus.OK);
        } else {
            return new ResponseEntity<AccountResource>(HttpStatus.NOT_FOUND);
        }
    }
    
    /**
     * Returns the account that matches the given name
     * @param accountName the given name
     * @return the account with the given name or a NOT_FOUND error
     */
    @RequestMapping( value="/name",
                method = RequestMethod.POST)
    @PreAuthorize("permitAll")
    public ResponseEntity<AccountResource> getAccountByName(
            @RequestParam(value="accountName", required = true) String accountName
    ) {
        Account account = accountService.findByAccountName(accountName);
        if(account != null)
        {
            AccountResource res = new AccountResourceAsm().toResource(account);
            return new ResponseEntity<AccountResource>(res, HttpStatus.OK);
        } else {
            return new ResponseEntity<AccountResource>(HttpStatus.NOT_FOUND);
        }
    }
    
    /**
     * Returns a List of all activated accounts
     * @param name if this parameter isn't empty, return the activated account that matches this name
     * @return a List of activated accounts or a single activated account 
     */
    @RequestMapping( value="/activated",
                method = RequestMethod.GET)
    @PreAuthorize("permitAll")
    public ResponseEntity<AccountListResource> findAllActivatedAccounts(@RequestParam(value="name", required = false) String name) {
        AccountList list = null;
        if(name == null) {
            list = accountService.findAllActivatedAccounts();
        } else {
            Account account = accountService.findActivatedByAccountName(name);
            if(account == null) {
                list = new AccountList(new ArrayList<Account>());
            } else {
                list = new AccountList(Arrays.asList(account));
            }
        }
        AccountListResource res = new AccountListResourceAsm().toResource(list);
        return new ResponseEntity<AccountListResource>(res, HttpStatus.OK);
    }

    /**
     * Modifies the given user password
     * @param name the user that will have its password modified
     * @param password the old password in MD5
     * @param newPassword the new password in MD5
     * @return returns OK or CONFLICT
     */
    @RequestMapping(value="/modifyPassword",
    method = RequestMethod.POST)
    @PreAuthorize("permitAll")
    public ResponseEntity modifyAccountPassword(
            @RequestParam(value="name", required = true) String name,
            @RequestParam(value="password", required = true) String password,
            @RequestParam(value="new_password", required = true) String newPassword) {
        if(!accountService.isAccountCorrect(name, password)) {
            return new ResponseEntity(HttpStatus.CONFLICT);
        }else{
            accountService.modifyPassword(name, newPassword);
        }
        return new ResponseEntity(HttpStatus.OK);
    }

}
